diff options
Diffstat (limited to 'libraries/evas/src/lib/canvas')
37 files changed, 35786 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/canvas/Makefile.am b/libraries/evas/src/lib/canvas/Makefile.am new file mode 100644 index 0000000..79544aa --- /dev/null +++ b/libraries/evas/src/lib/canvas/Makefile.am | |||
@@ -0,0 +1,68 @@ | |||
1 | MAINTAINERCLEANFILES = Makefile.in | ||
2 | |||
3 | AM_CPPFLAGS = \ | ||
4 | -I. \ | ||
5 | -I$(top_srcdir)/src/lib \ | ||
6 | -I$(top_srcdir)/src/lib/include \ | ||
7 | -I$(top_srcdir)/src/lib/cserve \ | ||
8 | -DPACKAGE_BIN_DIR=\"$(bindir)\" \ | ||
9 | -DPACKAGE_LIB_DIR=\"$(libdir)\" \ | ||
10 | -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ | ||
11 | @WIN32_CPPFLAGS@ \ | ||
12 | @FREETYPE_CFLAGS@ \ | ||
13 | @EET_CFLAGS@ \ | ||
14 | @FONTCONFIG_CFLAGS@ \ | ||
15 | @EVAS_CFLAGS@ \ | ||
16 | @EINA_CFLAGS@ \ | ||
17 | @EVIL_CFLAGS@ \ | ||
18 | @PIXMAN_CFLAGS@ | ||
19 | |||
20 | noinst_LTLIBRARIES = libevas_canvas.la | ||
21 | libevas_canvas_la_SOURCES = \ | ||
22 | evas_callbacks.c \ | ||
23 | evas_clip.c \ | ||
24 | evas_data.c \ | ||
25 | evas_events.c \ | ||
26 | evas_filter.c \ | ||
27 | evas_focus.c \ | ||
28 | evas_key.c \ | ||
29 | evas_key_grab.c \ | ||
30 | evas_layer.c \ | ||
31 | evas_main.c \ | ||
32 | evas_name.c \ | ||
33 | evas_object_image.c \ | ||
34 | evas_object_main.c \ | ||
35 | evas_object_inform.c \ | ||
36 | evas_object_intercept.c \ | ||
37 | evas_object_line.c \ | ||
38 | evas_object_polygon.c \ | ||
39 | evas_object_rectangle.c \ | ||
40 | evas_object_smart.c \ | ||
41 | evas_object_smart_clipped.c \ | ||
42 | evas_object_box.c \ | ||
43 | evas_object_table.c \ | ||
44 | evas_object_text.c \ | ||
45 | evas_object_textblock.c \ | ||
46 | evas_object_grid.c \ | ||
47 | evas_font_dir.c \ | ||
48 | evas_rectangle.c \ | ||
49 | evas_render.c \ | ||
50 | evas_smart.c \ | ||
51 | evas_stack.c \ | ||
52 | evas_async_events.c \ | ||
53 | evas_stats.c \ | ||
54 | evas_touch_point.c \ | ||
55 | evas_map.c \ | ||
56 | evas_gl.c | ||
57 | |||
58 | #evas_object_textgrid.c | ||
59 | |||
60 | libevas_canvas_la_LIBADD = @EVAS_LIBS@ @EVIL_LIBS@ | ||
61 | |||
62 | if EVAS_USE_LINEBREAK | ||
63 | AM_CPPFLAGS += @LINEBREAK_CFLAGS@ | ||
64 | libevas_canvas_la_LIBADD += @LINEBREAK_LIBS@ | ||
65 | endif | ||
66 | |||
67 | clean-local: | ||
68 | rm -rf *.gcno | ||
diff --git a/libraries/evas/src/lib/canvas/Makefile.in b/libraries/evas/src/lib/canvas/Makefile.in new file mode 100644 index 0000000..0b4e15d --- /dev/null +++ b/libraries/evas/src/lib/canvas/Makefile.in | |||
@@ -0,0 +1,760 @@ | |||
1 | # Makefile.in generated by automake 1.11.1 from Makefile.am. | ||
2 | # @configure_input@ | ||
3 | |||
4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | ||
5 | # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, | ||
6 | # Inc. | ||
7 | # This Makefile.in is free software; the Free Software Foundation | ||
8 | # gives unlimited permission to copy and/or distribute it, | ||
9 | # with or without modifications, as long as this notice is preserved. | ||
10 | |||
11 | # This program is distributed in the hope that it will be useful, | ||
12 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without | ||
13 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
14 | # PARTICULAR PURPOSE. | ||
15 | |||
16 | @SET_MAKE@ | ||
17 | |||
18 | VPATH = @srcdir@ | ||
19 | pkgdatadir = $(datadir)/@PACKAGE@ | ||
20 | pkgincludedir = $(includedir)/@PACKAGE@ | ||
21 | pkglibdir = $(libdir)/@PACKAGE@ | ||
22 | pkglibexecdir = $(libexecdir)/@PACKAGE@ | ||
23 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd | ||
24 | install_sh_DATA = $(install_sh) -c -m 644 | ||
25 | install_sh_PROGRAM = $(install_sh) -c | ||
26 | install_sh_SCRIPT = $(install_sh) -c | ||
27 | INSTALL_HEADER = $(INSTALL_DATA) | ||
28 | transform = $(program_transform_name) | ||
29 | NORMAL_INSTALL = : | ||
30 | PRE_INSTALL = : | ||
31 | POST_INSTALL = : | ||
32 | NORMAL_UNINSTALL = : | ||
33 | PRE_UNINSTALL = : | ||
34 | POST_UNINSTALL = : | ||
35 | build_triplet = @build@ | ||
36 | host_triplet = @host@ | ||
37 | @EVAS_USE_LINEBREAK_TRUE@am__append_1 = @LINEBREAK_CFLAGS@ | ||
38 | @EVAS_USE_LINEBREAK_TRUE@am__append_2 = @LINEBREAK_LIBS@ | ||
39 | subdir = src/lib/canvas | ||
40 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | ||
41 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ||
42 | am__aclocal_m4_deps = $(top_srcdir)/m4/efl_attribute.m4 \ | ||
43 | $(top_srcdir)/m4/efl_coverage.m4 \ | ||
44 | $(top_srcdir)/m4/efl_doxygen.m4 \ | ||
45 | $(top_srcdir)/m4/efl_fnmatch.m4 \ | ||
46 | $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \ | ||
47 | $(top_srcdir)/m4/evas_check_engine.m4 \ | ||
48 | $(top_srcdir)/m4/evas_check_loader.m4 \ | ||
49 | $(top_srcdir)/m4/evas_converter.m4 \ | ||
50 | $(top_srcdir)/m4/evas_dither.m4 \ | ||
51 | $(top_srcdir)/m4/evas_scaler.m4 $(top_srcdir)/m4/libtool.m4 \ | ||
52 | $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ | ||
53 | $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ | ||
54 | $(top_srcdir)/configure.ac | ||
55 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ | ||
56 | $(ACLOCAL_M4) | ||
57 | mkinstalldirs = $(install_sh) -d | ||
58 | CONFIG_HEADER = $(top_builddir)/config.h | ||
59 | CONFIG_CLEAN_FILES = | ||
60 | CONFIG_CLEAN_VPATH_FILES = | ||
61 | LTLIBRARIES = $(noinst_LTLIBRARIES) | ||
62 | am__DEPENDENCIES_1 = | ||
63 | libevas_canvas_la_DEPENDENCIES = $(am__DEPENDENCIES_1) | ||
64 | am_libevas_canvas_la_OBJECTS = evas_callbacks.lo evas_clip.lo \ | ||
65 | evas_data.lo evas_events.lo evas_filter.lo evas_focus.lo \ | ||
66 | evas_key.lo evas_key_grab.lo evas_layer.lo evas_main.lo \ | ||
67 | evas_name.lo evas_object_image.lo evas_object_main.lo \ | ||
68 | evas_object_inform.lo evas_object_intercept.lo \ | ||
69 | evas_object_line.lo evas_object_polygon.lo \ | ||
70 | evas_object_rectangle.lo evas_object_smart.lo \ | ||
71 | evas_object_smart_clipped.lo evas_object_box.lo \ | ||
72 | evas_object_table.lo evas_object_text.lo \ | ||
73 | evas_object_textblock.lo evas_object_grid.lo evas_font_dir.lo \ | ||
74 | evas_rectangle.lo evas_render.lo evas_smart.lo evas_stack.lo \ | ||
75 | evas_async_events.lo evas_stats.lo evas_touch_point.lo \ | ||
76 | evas_map.lo evas_gl.lo | ||
77 | libevas_canvas_la_OBJECTS = $(am_libevas_canvas_la_OBJECTS) | ||
78 | AM_V_lt = $(am__v_lt_$(V)) | ||
79 | am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) | ||
80 | am__v_lt_0 = --silent | ||
81 | DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) | ||
82 | depcomp = $(SHELL) $(top_srcdir)/depcomp | ||
83 | am__depfiles_maybe = depfiles | ||
84 | am__mv = mv -f | ||
85 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ | ||
86 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) | ||
87 | LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ | ||
88 | $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ | ||
89 | $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ | ||
90 | $(AM_CFLAGS) $(CFLAGS) | ||
91 | AM_V_CC = $(am__v_CC_$(V)) | ||
92 | am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) | ||
93 | am__v_CC_0 = @echo " CC " $@; | ||
94 | AM_V_at = $(am__v_at_$(V)) | ||
95 | am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) | ||
96 | am__v_at_0 = @ | ||
97 | CCLD = $(CC) | ||
98 | LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ | ||
99 | $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ | ||
100 | $(AM_LDFLAGS) $(LDFLAGS) -o $@ | ||
101 | AM_V_CCLD = $(am__v_CCLD_$(V)) | ||
102 | am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) | ||
103 | am__v_CCLD_0 = @echo " CCLD " $@; | ||
104 | AM_V_GEN = $(am__v_GEN_$(V)) | ||
105 | am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) | ||
106 | am__v_GEN_0 = @echo " GEN " $@; | ||
107 | SOURCES = $(libevas_canvas_la_SOURCES) | ||
108 | DIST_SOURCES = $(libevas_canvas_la_SOURCES) | ||
109 | ETAGS = etags | ||
110 | CTAGS = ctags | ||
111 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | ||
112 | ACLOCAL = @ACLOCAL@ | ||
113 | ALLOCA = @ALLOCA@ | ||
114 | AMTAR = @AMTAR@ | ||
115 | AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ | ||
116 | AR = @AR@ | ||
117 | AS = @AS@ | ||
118 | AUTOCONF = @AUTOCONF@ | ||
119 | AUTOHEADER = @AUTOHEADER@ | ||
120 | AUTOMAKE = @AUTOMAKE@ | ||
121 | AWK = @AWK@ | ||
122 | CC = @CC@ | ||
123 | CCDEPMODE = @CCDEPMODE@ | ||
124 | CFLAGS = @CFLAGS@ | ||
125 | CHECK_CFLAGS = @CHECK_CFLAGS@ | ||
126 | CHECK_LIBS = @CHECK_LIBS@ | ||
127 | CPP = @CPP@ | ||
128 | CPPFLAGS = @CPPFLAGS@ | ||
129 | CXX = @CXX@ | ||
130 | CXXCPP = @CXXCPP@ | ||
131 | CXXDEPMODE = @CXXDEPMODE@ | ||
132 | CXXFLAGS = @CXXFLAGS@ | ||
133 | CYGPATH_W = @CYGPATH_W@ | ||
134 | DEFS = @DEFS@ | ||
135 | DEPDIR = @DEPDIR@ | ||
136 | DIRECTFB_CFLAGS = @DIRECTFB_CFLAGS@ | ||
137 | DIRECTFB_LIBS = @DIRECTFB_LIBS@ | ||
138 | DLLTOOL = @DLLTOOL@ | ||
139 | DSYMUTIL = @DSYMUTIL@ | ||
140 | DUMPBIN = @DUMPBIN@ | ||
141 | ECHO_C = @ECHO_C@ | ||
142 | ECHO_N = @ECHO_N@ | ||
143 | ECHO_T = @ECHO_T@ | ||
144 | ECORE_EVAS_CFLAGS = @ECORE_EVAS_CFLAGS@ | ||
145 | ECORE_EVAS_LIBS = @ECORE_EVAS_LIBS@ | ||
146 | EDB_CFLAGS = @EDB_CFLAGS@ | ||
147 | EDB_LIBS = @EDB_LIBS@ | ||
148 | EDJE_CFLAGS = @EDJE_CFLAGS@ | ||
149 | EDJE_LIBS = @EDJE_LIBS@ | ||
150 | EET_CFLAGS = @EET_CFLAGS@ | ||
151 | EET_LIBS = @EET_LIBS@ | ||
152 | EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@ | ||
153 | EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@ | ||
154 | EFL_FNMATCH_LIBS = @EFL_FNMATCH_LIBS@ | ||
155 | EGREP = @EGREP@ | ||
156 | EINA_CFLAGS = @EINA_CFLAGS@ | ||
157 | EINA_LIBS = @EINA_LIBS@ | ||
158 | EVAS_CFLAGS = @EVAS_CFLAGS@ | ||
159 | EVAS_LIBS = @EVAS_LIBS@ | ||
160 | EVAS_SSE3_CFLAGS = @EVAS_SSE3_CFLAGS@ | ||
161 | EVIL_CFLAGS = @EVIL_CFLAGS@ | ||
162 | EVIL_LIBS = @EVIL_LIBS@ | ||
163 | EXEEXT = @EXEEXT@ | ||
164 | FGREP = @FGREP@ | ||
165 | FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@ | ||
166 | FONTCONFIG_LIBS = @FONTCONFIG_LIBS@ | ||
167 | FREETYPE_CFLAGS = @FREETYPE_CFLAGS@ | ||
168 | FREETYPE_LIBS = @FREETYPE_LIBS@ | ||
169 | FRIBIDI_CFLAGS = @FRIBIDI_CFLAGS@ | ||
170 | FRIBIDI_LIBS = @FRIBIDI_LIBS@ | ||
171 | GL_EET_CFLAGS = @GL_EET_CFLAGS@ | ||
172 | GL_EET_LIBS = @GL_EET_LIBS@ | ||
173 | GREP = @GREP@ | ||
174 | HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@ | ||
175 | HARFBUZZ_LIBS = @HARFBUZZ_LIBS@ | ||
176 | INSTALL = @INSTALL@ | ||
177 | INSTALL_DATA = @INSTALL_DATA@ | ||
178 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ | ||
179 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ | ||
180 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ | ||
181 | LD = @LD@ | ||
182 | LDFLAGS = @LDFLAGS@ | ||
183 | LIBOBJS = @LIBOBJS@ | ||
184 | LIBS = @LIBS@ | ||
185 | LIBTOOL = @LIBTOOL@ | ||
186 | LINEBREAK_CFLAGS = @LINEBREAK_CFLAGS@ | ||
187 | LINEBREAK_LIBS = @LINEBREAK_LIBS@ | ||
188 | LIPO = @LIPO@ | ||
189 | LN_S = @LN_S@ | ||
190 | LTLIBOBJS = @LTLIBOBJS@ | ||
191 | MAKEINFO = @MAKEINFO@ | ||
192 | MKDIR_P = @MKDIR_P@ | ||
193 | MODULE_ARCH = @MODULE_ARCH@ | ||
194 | NM = @NM@ | ||
195 | NMEDIT = @NMEDIT@ | ||
196 | OBJC = @OBJC@ | ||
197 | OBJCDEPMODE = @OBJCDEPMODE@ | ||
198 | OBJCFLAGS = @OBJCFLAGS@ | ||
199 | OBJDUMP = @OBJDUMP@ | ||
200 | OBJEXT = @OBJEXT@ | ||
201 | OTOOL = @OTOOL@ | ||
202 | OTOOL64 = @OTOOL64@ | ||
203 | PACKAGE = @PACKAGE@ | ||
204 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ | ||
205 | PACKAGE_NAME = @PACKAGE_NAME@ | ||
206 | PACKAGE_STRING = @PACKAGE_STRING@ | ||
207 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ | ||
208 | PACKAGE_URL = @PACKAGE_URL@ | ||
209 | PACKAGE_VERSION = @PACKAGE_VERSION@ | ||
210 | PATH_SEPARATOR = @PATH_SEPARATOR@ | ||
211 | PIXMAN_CFLAGS = @PIXMAN_CFLAGS@ | ||
212 | PIXMAN_LIBS = @PIXMAN_LIBS@ | ||
213 | PKG_CONFIG = @PKG_CONFIG@ | ||
214 | PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ | ||
215 | PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ | ||
216 | PNG_CFLAGS = @PNG_CFLAGS@ | ||
217 | PNG_LIBS = @PNG_LIBS@ | ||
218 | RANLIB = @RANLIB@ | ||
219 | SDL_CFLAGS = @SDL_CFLAGS@ | ||
220 | SDL_LIBS = @SDL_LIBS@ | ||
221 | SED = @SED@ | ||
222 | SET_MAKE = @SET_MAKE@ | ||
223 | SHELL = @SHELL@ | ||
224 | SHM_OPEN_LINK = @SHM_OPEN_LINK@ | ||
225 | STRIP = @STRIP@ | ||
226 | SVG_CFLAGS = @SVG_CFLAGS@ | ||
227 | SVG_LIBS = @SVG_LIBS@ | ||
228 | VALGRIND_CFLAGS = @VALGRIND_CFLAGS@ | ||
229 | VALGRIND_LIBS = @VALGRIND_LIBS@ | ||
230 | VERSION = @VERSION@ | ||
231 | VMAJ = @VMAJ@ | ||
232 | WIN32_CFLAGS = @WIN32_CFLAGS@ | ||
233 | WIN32_CPPFLAGS = @WIN32_CPPFLAGS@ | ||
234 | XCB_CFLAGS = @XCB_CFLAGS@ | ||
235 | XCB_GL_CFLAGS = @XCB_GL_CFLAGS@ | ||
236 | XCB_GL_LIBS = @XCB_GL_LIBS@ | ||
237 | XCB_LIBS = @XCB_LIBS@ | ||
238 | XEXT_CFLAGS = @XEXT_CFLAGS@ | ||
239 | XEXT_LIBS = @XEXT_LIBS@ | ||
240 | XMKMF = @XMKMF@ | ||
241 | X_CFLAGS = @X_CFLAGS@ | ||
242 | X_EXTRA_LIBS = @X_EXTRA_LIBS@ | ||
243 | X_LIBS = @X_LIBS@ | ||
244 | X_PRE_LIBS = @X_PRE_LIBS@ | ||
245 | abs_builddir = @abs_builddir@ | ||
246 | abs_srcdir = @abs_srcdir@ | ||
247 | abs_top_builddir = @abs_top_builddir@ | ||
248 | abs_top_srcdir = @abs_top_srcdir@ | ||
249 | ac_ct_CC = @ac_ct_CC@ | ||
250 | ac_ct_CXX = @ac_ct_CXX@ | ||
251 | ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ | ||
252 | ac_ct_OBJC = @ac_ct_OBJC@ | ||
253 | altivec_cflags = @altivec_cflags@ | ||
254 | am__include = @am__include@ | ||
255 | am__leading_dot = @am__leading_dot@ | ||
256 | am__quote = @am__quote@ | ||
257 | am__tar = @am__tar@ | ||
258 | am__untar = @am__untar@ | ||
259 | bindir = @bindir@ | ||
260 | build = @build@ | ||
261 | build_alias = @build_alias@ | ||
262 | build_cpu = @build_cpu@ | ||
263 | build_os = @build_os@ | ||
264 | build_vendor = @build_vendor@ | ||
265 | builddir = @builddir@ | ||
266 | datadir = @datadir@ | ||
267 | datarootdir = @datarootdir@ | ||
268 | dlopen_libs = @dlopen_libs@ | ||
269 | docdir = @docdir@ | ||
270 | dvidir = @dvidir@ | ||
271 | edje_cc = @edje_cc@ | ||
272 | efl_doxygen = @efl_doxygen@ | ||
273 | efl_have_doxygen = @efl_have_doxygen@ | ||
274 | evas_engine_buffer_cflags = @evas_engine_buffer_cflags@ | ||
275 | evas_engine_buffer_libs = @evas_engine_buffer_libs@ | ||
276 | evas_engine_direct3d_cflags = @evas_engine_direct3d_cflags@ | ||
277 | evas_engine_direct3d_libs = @evas_engine_direct3d_libs@ | ||
278 | evas_engine_directfb_cflags = @evas_engine_directfb_cflags@ | ||
279 | evas_engine_directfb_libs = @evas_engine_directfb_libs@ | ||
280 | evas_engine_fb_cflags = @evas_engine_fb_cflags@ | ||
281 | evas_engine_fb_libs = @evas_engine_fb_libs@ | ||
282 | evas_engine_gl_cocoa_cflags = @evas_engine_gl_cocoa_cflags@ | ||
283 | evas_engine_gl_cocoa_libs = @evas_engine_gl_cocoa_libs@ | ||
284 | evas_engine_gl_common_libs = @evas_engine_gl_common_libs@ | ||
285 | evas_engine_gl_sdl_cflags = @evas_engine_gl_sdl_cflags@ | ||
286 | evas_engine_gl_sdl_libs = @evas_engine_gl_sdl_libs@ | ||
287 | evas_engine_gl_xcb_cflags = @evas_engine_gl_xcb_cflags@ | ||
288 | evas_engine_gl_xcb_libs = @evas_engine_gl_xcb_libs@ | ||
289 | evas_engine_gl_xlib_cflags = @evas_engine_gl_xlib_cflags@ | ||
290 | evas_engine_gl_xlib_libs = @evas_engine_gl_xlib_libs@ | ||
291 | evas_engine_psl1ght_cflags = @evas_engine_psl1ght_cflags@ | ||
292 | evas_engine_psl1ght_libs = @evas_engine_psl1ght_libs@ | ||
293 | evas_engine_software_16_ddraw_cflags = @evas_engine_software_16_ddraw_cflags@ | ||
294 | evas_engine_software_16_ddraw_libs = @evas_engine_software_16_ddraw_libs@ | ||
295 | evas_engine_software_16_sdl_cflags = @evas_engine_software_16_sdl_cflags@ | ||
296 | evas_engine_software_16_sdl_libs = @evas_engine_software_16_sdl_libs@ | ||
297 | evas_engine_software_16_wince_cflags = @evas_engine_software_16_wince_cflags@ | ||
298 | evas_engine_software_16_wince_libs = @evas_engine_software_16_wince_libs@ | ||
299 | evas_engine_software_16_x11_cflags = @evas_engine_software_16_x11_cflags@ | ||
300 | evas_engine_software_16_x11_libs = @evas_engine_software_16_x11_libs@ | ||
301 | evas_engine_software_8_x11_cflags = @evas_engine_software_8_x11_cflags@ | ||
302 | evas_engine_software_8_x11_libs = @evas_engine_software_8_x11_libs@ | ||
303 | evas_engine_software_ddraw_cflags = @evas_engine_software_ddraw_cflags@ | ||
304 | evas_engine_software_ddraw_libs = @evas_engine_software_ddraw_libs@ | ||
305 | evas_engine_software_gdi_cflags = @evas_engine_software_gdi_cflags@ | ||
306 | evas_engine_software_gdi_libs = @evas_engine_software_gdi_libs@ | ||
307 | evas_engine_software_sdl_cflags = @evas_engine_software_sdl_cflags@ | ||
308 | evas_engine_software_sdl_libs = @evas_engine_software_sdl_libs@ | ||
309 | evas_engine_software_xcb_cflags = @evas_engine_software_xcb_cflags@ | ||
310 | evas_engine_software_xcb_libs = @evas_engine_software_xcb_libs@ | ||
311 | evas_engine_software_xlib_cflags = @evas_engine_software_xlib_cflags@ | ||
312 | evas_engine_software_xlib_libs = @evas_engine_software_xlib_libs@ | ||
313 | evas_image_loader_bmp_cflags = @evas_image_loader_bmp_cflags@ | ||
314 | evas_image_loader_bmp_libs = @evas_image_loader_bmp_libs@ | ||
315 | evas_image_loader_edb_cflags = @evas_image_loader_edb_cflags@ | ||
316 | evas_image_loader_edb_libs = @evas_image_loader_edb_libs@ | ||
317 | evas_image_loader_eet_cflags = @evas_image_loader_eet_cflags@ | ||
318 | evas_image_loader_eet_libs = @evas_image_loader_eet_libs@ | ||
319 | evas_image_loader_generic_cflags = @evas_image_loader_generic_cflags@ | ||
320 | evas_image_loader_generic_libs = @evas_image_loader_generic_libs@ | ||
321 | evas_image_loader_gif_cflags = @evas_image_loader_gif_cflags@ | ||
322 | evas_image_loader_gif_libs = @evas_image_loader_gif_libs@ | ||
323 | evas_image_loader_ico_cflags = @evas_image_loader_ico_cflags@ | ||
324 | evas_image_loader_ico_libs = @evas_image_loader_ico_libs@ | ||
325 | evas_image_loader_jpeg_cflags = @evas_image_loader_jpeg_cflags@ | ||
326 | evas_image_loader_jpeg_libs = @evas_image_loader_jpeg_libs@ | ||
327 | evas_image_loader_pmaps_cflags = @evas_image_loader_pmaps_cflags@ | ||
328 | evas_image_loader_pmaps_libs = @evas_image_loader_pmaps_libs@ | ||
329 | evas_image_loader_png_cflags = @evas_image_loader_png_cflags@ | ||
330 | evas_image_loader_png_libs = @evas_image_loader_png_libs@ | ||
331 | evas_image_loader_psd_cflags = @evas_image_loader_psd_cflags@ | ||
332 | evas_image_loader_psd_libs = @evas_image_loader_psd_libs@ | ||
333 | evas_image_loader_svg_cflags = @evas_image_loader_svg_cflags@ | ||
334 | evas_image_loader_svg_libs = @evas_image_loader_svg_libs@ | ||
335 | evas_image_loader_tga_cflags = @evas_image_loader_tga_cflags@ | ||
336 | evas_image_loader_tga_libs = @evas_image_loader_tga_libs@ | ||
337 | evas_image_loader_tiff_cflags = @evas_image_loader_tiff_cflags@ | ||
338 | evas_image_loader_tiff_libs = @evas_image_loader_tiff_libs@ | ||
339 | evas_image_loader_wbmp_cflags = @evas_image_loader_wbmp_cflags@ | ||
340 | evas_image_loader_wbmp_libs = @evas_image_loader_wbmp_libs@ | ||
341 | evas_image_loader_xpm_cflags = @evas_image_loader_xpm_cflags@ | ||
342 | evas_image_loader_xpm_libs = @evas_image_loader_xpm_libs@ | ||
343 | exec_prefix = @exec_prefix@ | ||
344 | have_evas_engine_gl_x11 = @have_evas_engine_gl_x11@ | ||
345 | have_evas_engine_gl_xcb = @have_evas_engine_gl_xcb@ | ||
346 | have_evas_engine_gl_xlib = @have_evas_engine_gl_xlib@ | ||
347 | have_evas_engine_software_x11 = @have_evas_engine_software_x11@ | ||
348 | have_evas_engine_software_xcb = @have_evas_engine_software_xcb@ | ||
349 | have_evas_engine_software_xlib = @have_evas_engine_software_xlib@ | ||
350 | have_lcov = @have_lcov@ | ||
351 | host = @host@ | ||
352 | host_alias = @host_alias@ | ||
353 | host_cpu = @host_cpu@ | ||
354 | host_os = @host_os@ | ||
355 | host_vendor = @host_vendor@ | ||
356 | htmldir = @htmldir@ | ||
357 | includedir = @includedir@ | ||
358 | infodir = @infodir@ | ||
359 | install_sh = @install_sh@ | ||
360 | libdir = @libdir@ | ||
361 | libexecdir = @libexecdir@ | ||
362 | localedir = @localedir@ | ||
363 | localstatedir = @localstatedir@ | ||
364 | lt_ECHO = @lt_ECHO@ | ||
365 | lt_enable_auto_import = @lt_enable_auto_import@ | ||
366 | mandir = @mandir@ | ||
367 | mkdir_p = @mkdir_p@ | ||
368 | oldincludedir = @oldincludedir@ | ||
369 | pdfdir = @pdfdir@ | ||
370 | pkgconfig_requires_private = @pkgconfig_requires_private@ | ||
371 | prefix = @prefix@ | ||
372 | program_transform_name = @program_transform_name@ | ||
373 | psdir = @psdir@ | ||
374 | pthread_cflags = @pthread_cflags@ | ||
375 | pthread_libs = @pthread_libs@ | ||
376 | release_info = @release_info@ | ||
377 | requirement_evas = @requirement_evas@ | ||
378 | sbindir = @sbindir@ | ||
379 | sharedstatedir = @sharedstatedir@ | ||
380 | srcdir = @srcdir@ | ||
381 | sysconfdir = @sysconfdir@ | ||
382 | target_alias = @target_alias@ | ||
383 | top_build_prefix = @top_build_prefix@ | ||
384 | top_builddir = @top_builddir@ | ||
385 | top_srcdir = @top_srcdir@ | ||
386 | version_info = @version_info@ | ||
387 | MAINTAINERCLEANFILES = Makefile.in | ||
388 | AM_CPPFLAGS = -I. -I$(top_srcdir)/src/lib \ | ||
389 | -I$(top_srcdir)/src/lib/include -I$(top_srcdir)/src/lib/cserve \ | ||
390 | -DPACKAGE_BIN_DIR=\"$(bindir)\" \ | ||
391 | -DPACKAGE_LIB_DIR=\"$(libdir)\" \ | ||
392 | -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" @WIN32_CPPFLAGS@ \ | ||
393 | @FREETYPE_CFLAGS@ @EET_CFLAGS@ @FONTCONFIG_CFLAGS@ \ | ||
394 | @EVAS_CFLAGS@ @EINA_CFLAGS@ @EVIL_CFLAGS@ @PIXMAN_CFLAGS@ \ | ||
395 | $(am__append_1) | ||
396 | noinst_LTLIBRARIES = libevas_canvas.la | ||
397 | libevas_canvas_la_SOURCES = \ | ||
398 | evas_callbacks.c \ | ||
399 | evas_clip.c \ | ||
400 | evas_data.c \ | ||
401 | evas_events.c \ | ||
402 | evas_filter.c \ | ||
403 | evas_focus.c \ | ||
404 | evas_key.c \ | ||
405 | evas_key_grab.c \ | ||
406 | evas_layer.c \ | ||
407 | evas_main.c \ | ||
408 | evas_name.c \ | ||
409 | evas_object_image.c \ | ||
410 | evas_object_main.c \ | ||
411 | evas_object_inform.c \ | ||
412 | evas_object_intercept.c \ | ||
413 | evas_object_line.c \ | ||
414 | evas_object_polygon.c \ | ||
415 | evas_object_rectangle.c \ | ||
416 | evas_object_smart.c \ | ||
417 | evas_object_smart_clipped.c \ | ||
418 | evas_object_box.c \ | ||
419 | evas_object_table.c \ | ||
420 | evas_object_text.c \ | ||
421 | evas_object_textblock.c \ | ||
422 | evas_object_grid.c \ | ||
423 | evas_font_dir.c \ | ||
424 | evas_rectangle.c \ | ||
425 | evas_render.c \ | ||
426 | evas_smart.c \ | ||
427 | evas_stack.c \ | ||
428 | evas_async_events.c \ | ||
429 | evas_stats.c \ | ||
430 | evas_touch_point.c \ | ||
431 | evas_map.c \ | ||
432 | evas_gl.c | ||
433 | |||
434 | |||
435 | #evas_object_textgrid.c | ||
436 | libevas_canvas_la_LIBADD = @EVAS_LIBS@ @EVIL_LIBS@ $(am__append_2) | ||
437 | all: all-am | ||
438 | |||
439 | .SUFFIXES: | ||
440 | .SUFFIXES: .c .lo .o .obj | ||
441 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) | ||
442 | @for dep in $?; do \ | ||
443 | case '$(am__configure_deps)' in \ | ||
444 | *$$dep*) \ | ||
445 | ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ | ||
446 | && { if test -f $@; then exit 0; else break; fi; }; \ | ||
447 | exit 1;; \ | ||
448 | esac; \ | ||
449 | done; \ | ||
450 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/canvas/Makefile'; \ | ||
451 | $(am__cd) $(top_srcdir) && \ | ||
452 | $(AUTOMAKE) --gnu src/lib/canvas/Makefile | ||
453 | .PRECIOUS: Makefile | ||
454 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | ||
455 | @case '$?' in \ | ||
456 | *config.status*) \ | ||
457 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ | ||
458 | *) \ | ||
459 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ | ||
460 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ | ||
461 | esac; | ||
462 | |||
463 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) | ||
464 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
465 | |||
466 | $(top_srcdir)/configure: $(am__configure_deps) | ||
467 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
468 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) | ||
469 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
470 | $(am__aclocal_m4_deps): | ||
471 | |||
472 | clean-noinstLTLIBRARIES: | ||
473 | -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) | ||
474 | @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ | ||
475 | dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ | ||
476 | test "$$dir" != "$$p" || dir=.; \ | ||
477 | echo "rm -f \"$${dir}/so_locations\""; \ | ||
478 | rm -f "$${dir}/so_locations"; \ | ||
479 | done | ||
480 | libevas_canvas.la: $(libevas_canvas_la_OBJECTS) $(libevas_canvas_la_DEPENDENCIES) | ||
481 | $(AM_V_CCLD)$(LINK) $(libevas_canvas_la_OBJECTS) $(libevas_canvas_la_LIBADD) $(LIBS) | ||
482 | |||
483 | mostlyclean-compile: | ||
484 | -rm -f *.$(OBJEXT) | ||
485 | |||
486 | distclean-compile: | ||
487 | -rm -f *.tab.c | ||
488 | |||
489 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_async_events.Plo@am__quote@ | ||
490 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_callbacks.Plo@am__quote@ | ||
491 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_clip.Plo@am__quote@ | ||
492 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_data.Plo@am__quote@ | ||
493 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_events.Plo@am__quote@ | ||
494 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_filter.Plo@am__quote@ | ||
495 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_focus.Plo@am__quote@ | ||
496 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_font_dir.Plo@am__quote@ | ||
497 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_gl.Plo@am__quote@ | ||
498 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_key.Plo@am__quote@ | ||
499 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_key_grab.Plo@am__quote@ | ||
500 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_layer.Plo@am__quote@ | ||
501 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_main.Plo@am__quote@ | ||
502 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_map.Plo@am__quote@ | ||
503 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_name.Plo@am__quote@ | ||
504 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_box.Plo@am__quote@ | ||
505 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_grid.Plo@am__quote@ | ||
506 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_image.Plo@am__quote@ | ||
507 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_inform.Plo@am__quote@ | ||
508 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_intercept.Plo@am__quote@ | ||
509 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_line.Plo@am__quote@ | ||
510 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_main.Plo@am__quote@ | ||
511 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_polygon.Plo@am__quote@ | ||
512 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_rectangle.Plo@am__quote@ | ||
513 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_smart.Plo@am__quote@ | ||
514 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_smart_clipped.Plo@am__quote@ | ||
515 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_table.Plo@am__quote@ | ||
516 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_text.Plo@am__quote@ | ||
517 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_object_textblock.Plo@am__quote@ | ||
518 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_rectangle.Plo@am__quote@ | ||
519 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_render.Plo@am__quote@ | ||
520 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_smart.Plo@am__quote@ | ||
521 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_stack.Plo@am__quote@ | ||
522 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_stats.Plo@am__quote@ | ||
523 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evas_touch_point.Plo@am__quote@ | ||
524 | |||
525 | .c.o: | ||
526 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< | ||
527 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po | ||
528 | @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ | ||
529 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | ||
530 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
531 | @am__fastdepCC_FALSE@ $(COMPILE) -c $< | ||
532 | |||
533 | .c.obj: | ||
534 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` | ||
535 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po | ||
536 | @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ | ||
537 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | ||
538 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
539 | @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` | ||
540 | |||
541 | .c.lo: | ||
542 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< | ||
543 | @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo | ||
544 | @am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ | ||
545 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ | ||
546 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
547 | @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< | ||
548 | |||
549 | mostlyclean-libtool: | ||
550 | -rm -f *.lo | ||
551 | |||
552 | clean-libtool: | ||
553 | -rm -rf .libs _libs | ||
554 | |||
555 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) | ||
556 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
557 | unique=`for i in $$list; do \ | ||
558 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
559 | done | \ | ||
560 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ | ||
561 | END { if (nonempty) { for (i in files) print i; }; }'`; \ | ||
562 | mkid -fID $$unique | ||
563 | tags: TAGS | ||
564 | |||
565 | TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ | ||
566 | $(TAGS_FILES) $(LISP) | ||
567 | set x; \ | ||
568 | here=`pwd`; \ | ||
569 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
570 | unique=`for i in $$list; do \ | ||
571 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
572 | done | \ | ||
573 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ | ||
574 | END { if (nonempty) { for (i in files) print i; }; }'`; \ | ||
575 | shift; \ | ||
576 | if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ | ||
577 | test -n "$$unique" || unique=$$empty_fix; \ | ||
578 | if test $$# -gt 0; then \ | ||
579 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | ||
580 | "$$@" $$unique; \ | ||
581 | else \ | ||
582 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | ||
583 | $$unique; \ | ||
584 | fi; \ | ||
585 | fi | ||
586 | ctags: CTAGS | ||
587 | CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ | ||
588 | $(TAGS_FILES) $(LISP) | ||
589 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
590 | unique=`for i in $$list; do \ | ||
591 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
592 | done | \ | ||
593 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ | ||
594 | END { if (nonempty) { for (i in files) print i; }; }'`; \ | ||
595 | test -z "$(CTAGS_ARGS)$$unique" \ | ||
596 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ | ||
597 | $$unique | ||
598 | |||
599 | GTAGS: | ||
600 | here=`$(am__cd) $(top_builddir) && pwd` \ | ||
601 | && $(am__cd) $(top_srcdir) \ | ||
602 | && gtags -i $(GTAGS_ARGS) "$$here" | ||
603 | |||
604 | distclean-tags: | ||
605 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags | ||
606 | |||
607 | distdir: $(DISTFILES) | ||
608 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ | ||
609 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ | ||
610 | list='$(DISTFILES)'; \ | ||
611 | dist_files=`for file in $$list; do echo $$file; done | \ | ||
612 | sed -e "s|^$$srcdirstrip/||;t" \ | ||
613 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ | ||
614 | case $$dist_files in \ | ||
615 | */*) $(MKDIR_P) `echo "$$dist_files" | \ | ||
616 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ | ||
617 | sort -u` ;; \ | ||
618 | esac; \ | ||
619 | for file in $$dist_files; do \ | ||
620 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ | ||
621 | if test -d $$d/$$file; then \ | ||
622 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ | ||
623 | if test -d "$(distdir)/$$file"; then \ | ||
624 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ | ||
625 | fi; \ | ||
626 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ | ||
627 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ | ||
628 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ | ||
629 | fi; \ | ||
630 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ | ||
631 | else \ | ||
632 | test -f "$(distdir)/$$file" \ | ||
633 | || cp -p $$d/$$file "$(distdir)/$$file" \ | ||
634 | || exit 1; \ | ||
635 | fi; \ | ||
636 | done | ||
637 | check-am: all-am | ||
638 | check: check-am | ||
639 | all-am: Makefile $(LTLIBRARIES) | ||
640 | installdirs: | ||
641 | install: install-am | ||
642 | install-exec: install-exec-am | ||
643 | install-data: install-data-am | ||
644 | uninstall: uninstall-am | ||
645 | |||
646 | install-am: all-am | ||
647 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am | ||
648 | |||
649 | installcheck: installcheck-am | ||
650 | install-strip: | ||
651 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ | ||
652 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ | ||
653 | `test -z '$(STRIP)' || \ | ||
654 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install | ||
655 | mostlyclean-generic: | ||
656 | |||
657 | clean-generic: | ||
658 | |||
659 | distclean-generic: | ||
660 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) | ||
661 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) | ||
662 | |||
663 | maintainer-clean-generic: | ||
664 | @echo "This command is intended for maintainers to use" | ||
665 | @echo "it deletes files that may require special tools to rebuild." | ||
666 | -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) | ||
667 | clean: clean-am | ||
668 | |||
669 | clean-am: clean-generic clean-libtool clean-local \ | ||
670 | clean-noinstLTLIBRARIES mostlyclean-am | ||
671 | |||
672 | distclean: distclean-am | ||
673 | -rm -rf ./$(DEPDIR) | ||
674 | -rm -f Makefile | ||
675 | distclean-am: clean-am distclean-compile distclean-generic \ | ||
676 | distclean-tags | ||
677 | |||
678 | dvi: dvi-am | ||
679 | |||
680 | dvi-am: | ||
681 | |||
682 | html: html-am | ||
683 | |||
684 | html-am: | ||
685 | |||
686 | info: info-am | ||
687 | |||
688 | info-am: | ||
689 | |||
690 | install-data-am: | ||
691 | |||
692 | install-dvi: install-dvi-am | ||
693 | |||
694 | install-dvi-am: | ||
695 | |||
696 | install-exec-am: | ||
697 | |||
698 | install-html: install-html-am | ||
699 | |||
700 | install-html-am: | ||
701 | |||
702 | install-info: install-info-am | ||
703 | |||
704 | install-info-am: | ||
705 | |||
706 | install-man: | ||
707 | |||
708 | install-pdf: install-pdf-am | ||
709 | |||
710 | install-pdf-am: | ||
711 | |||
712 | install-ps: install-ps-am | ||
713 | |||
714 | install-ps-am: | ||
715 | |||
716 | installcheck-am: | ||
717 | |||
718 | maintainer-clean: maintainer-clean-am | ||
719 | -rm -rf ./$(DEPDIR) | ||
720 | -rm -f Makefile | ||
721 | maintainer-clean-am: distclean-am maintainer-clean-generic | ||
722 | |||
723 | mostlyclean: mostlyclean-am | ||
724 | |||
725 | mostlyclean-am: mostlyclean-compile mostlyclean-generic \ | ||
726 | mostlyclean-libtool | ||
727 | |||
728 | pdf: pdf-am | ||
729 | |||
730 | pdf-am: | ||
731 | |||
732 | ps: ps-am | ||
733 | |||
734 | ps-am: | ||
735 | |||
736 | uninstall-am: | ||
737 | |||
738 | .MAKE: install-am install-strip | ||
739 | |||
740 | .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ | ||
741 | clean-libtool clean-local clean-noinstLTLIBRARIES ctags \ | ||
742 | distclean distclean-compile distclean-generic \ | ||
743 | distclean-libtool distclean-tags distdir dvi dvi-am html \ | ||
744 | html-am info info-am install install-am install-data \ | ||
745 | install-data-am install-dvi install-dvi-am install-exec \ | ||
746 | install-exec-am install-html install-html-am install-info \ | ||
747 | install-info-am install-man install-pdf install-pdf-am \ | ||
748 | install-ps install-ps-am install-strip installcheck \ | ||
749 | installcheck-am installdirs maintainer-clean \ | ||
750 | maintainer-clean-generic mostlyclean mostlyclean-compile \ | ||
751 | mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ | ||
752 | tags uninstall uninstall-am | ||
753 | |||
754 | |||
755 | clean-local: | ||
756 | rm -rf *.gcno | ||
757 | |||
758 | # Tell versions [3.59,3.63) of GNU make to not export all variables. | ||
759 | # Otherwise a system limit (for SysV at least) may be exceeded. | ||
760 | .NOEXPORT: | ||
diff --git a/libraries/evas/src/lib/canvas/evas_async_events.c b/libraries/evas/src/lib/canvas/evas_async_events.c new file mode 100644 index 0000000..bd2e3a8 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_async_events.c | |||
@@ -0,0 +1,173 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #ifdef BUILD_ASYNC_EVENTS | ||
6 | |||
7 | # ifndef _MSC_VER | ||
8 | # include <unistd.h> | ||
9 | # endif | ||
10 | # include <fcntl.h> | ||
11 | # include <errno.h> | ||
12 | |||
13 | #endif | ||
14 | |||
15 | #include "evas_common.h" | ||
16 | #include "evas_private.h" | ||
17 | |||
18 | #ifdef BUILD_ASYNC_EVENTS | ||
19 | |||
20 | static int _fd_write = -1; | ||
21 | static int _fd_read = -1; | ||
22 | |||
23 | static int _init_evas_event = 0; | ||
24 | |||
25 | typedef struct _Evas_Event_Async Evas_Event_Async; | ||
26 | |||
27 | struct _Evas_Event_Async | ||
28 | { | ||
29 | const void *target; | ||
30 | void *event_info; | ||
31 | Evas_Async_Events_Put_Cb func; | ||
32 | Evas_Callback_Type type; | ||
33 | }; | ||
34 | |||
35 | int | ||
36 | evas_async_events_init(void) | ||
37 | { | ||
38 | int filedes[2]; | ||
39 | |||
40 | _init_evas_event++; | ||
41 | if (_init_evas_event > 1) return _init_evas_event; | ||
42 | |||
43 | if (pipe(filedes) == -1) | ||
44 | { | ||
45 | _init_evas_event = 0; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | _fd_read = filedes[0]; | ||
50 | _fd_write = filedes[1]; | ||
51 | |||
52 | fcntl(_fd_read, F_SETFL, O_NONBLOCK); | ||
53 | |||
54 | return _init_evas_event; | ||
55 | } | ||
56 | |||
57 | int | ||
58 | evas_async_events_shutdown(void) | ||
59 | { | ||
60 | _init_evas_event--; | ||
61 | if (_init_evas_event > 0) return _init_evas_event; | ||
62 | |||
63 | close(_fd_read); | ||
64 | close(_fd_write); | ||
65 | _fd_read = -1; | ||
66 | _fd_write = -1; | ||
67 | |||
68 | return _init_evas_event; | ||
69 | } | ||
70 | |||
71 | #endif | ||
72 | |||
73 | EAPI int | ||
74 | evas_async_events_fd_get(void) | ||
75 | { | ||
76 | #ifdef BUILD_ASYNC_EVENTS | ||
77 | return _fd_read; | ||
78 | #else | ||
79 | return -1; | ||
80 | #endif | ||
81 | } | ||
82 | |||
83 | EAPI int | ||
84 | evas_async_events_process(void) | ||
85 | { | ||
86 | #ifdef BUILD_ASYNC_EVENTS | ||
87 | Evas_Event_Async *ev; | ||
88 | int check; | ||
89 | int count = 0; | ||
90 | |||
91 | if (_fd_read == -1) return 0; | ||
92 | |||
93 | do | ||
94 | { | ||
95 | check = read(_fd_read, &ev, sizeof (Evas_Event_Async *)); | ||
96 | |||
97 | if (check == sizeof (Evas_Event_Async *)) | ||
98 | { | ||
99 | if (ev->func) ev->func((void *)ev->target, ev->type, ev->event_info); | ||
100 | free(ev); | ||
101 | count++; | ||
102 | } | ||
103 | } | ||
104 | while (check > 0); | ||
105 | |||
106 | evas_cache_image_wakeup(); | ||
107 | |||
108 | if (check < 0) | ||
109 | { | ||
110 | switch (errno) | ||
111 | { | ||
112 | case EBADF: | ||
113 | case EINVAL: | ||
114 | case EIO: | ||
115 | case EISDIR: | ||
116 | _fd_read = -1; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | return count; | ||
121 | #else | ||
122 | return 0; | ||
123 | #endif | ||
124 | } | ||
125 | |||
126 | EAPI Eina_Bool | ||
127 | evas_async_events_put(const void *target, Evas_Callback_Type type, void *event_info, Evas_Async_Events_Put_Cb func) | ||
128 | { | ||
129 | #ifdef BUILD_ASYNC_EVENTS | ||
130 | Evas_Event_Async *ev; | ||
131 | ssize_t check; | ||
132 | Eina_Bool result = EINA_FALSE; | ||
133 | |||
134 | if (!func) return 0; | ||
135 | if (_fd_write == -1) return 0; | ||
136 | |||
137 | ev = calloc(1, sizeof (Evas_Event_Async)); | ||
138 | if (!ev) return 0; | ||
139 | |||
140 | ev->func = func; | ||
141 | ev->target = target; | ||
142 | ev->type = type; | ||
143 | ev->event_info = event_info; | ||
144 | |||
145 | do | ||
146 | { | ||
147 | check = write(_fd_write, &ev, sizeof (Evas_Event_Async*)); | ||
148 | } | ||
149 | while ((check != sizeof (Evas_Event_Async*)) && | ||
150 | ((errno == EINTR) || (errno == EAGAIN))); | ||
151 | |||
152 | evas_cache_image_wakeup(); | ||
153 | |||
154 | if (check == sizeof (Evas_Event_Async*)) | ||
155 | result = EINA_TRUE; | ||
156 | else | ||
157 | { | ||
158 | switch (errno) | ||
159 | { | ||
160 | case EBADF: | ||
161 | case EINVAL: | ||
162 | case EIO: | ||
163 | case EPIPE: | ||
164 | _fd_write = -1; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | return result; | ||
169 | #else | ||
170 | func((void*) target, type, event_info); | ||
171 | return EINA_TRUE; | ||
172 | #endif | ||
173 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_callbacks.c b/libraries/evas/src/lib/canvas/evas_callbacks.c new file mode 100644 index 0000000..33b93bc --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_callbacks.c | |||
@@ -0,0 +1,534 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | static void evas_object_event_callback_clear(Evas_Object *obj); | ||
5 | static void evas_event_callback_clear(Evas *e); | ||
6 | int _evas_event_counter = 0; | ||
7 | |||
8 | EVAS_MEMPOOL(_mp_fn); | ||
9 | EVAS_MEMPOOL(_mp_cb); | ||
10 | EVAS_MEMPOOL(_mp_pc); | ||
11 | |||
12 | void | ||
13 | _evas_post_event_callback_call(Evas *e) | ||
14 | { | ||
15 | Evas_Post_Callback *pc; | ||
16 | int skip = 0; | ||
17 | |||
18 | if (e->delete_me) return; | ||
19 | _evas_walk(e); | ||
20 | EINA_LIST_FREE(e->post_events, pc) | ||
21 | { | ||
22 | if ((!skip) && (!e->delete_me) && (!pc->delete_me)) | ||
23 | { | ||
24 | if (!pc->func((void*)pc->data, e)) skip = 1; | ||
25 | } | ||
26 | EVAS_MEMPOOL_FREE(_mp_pc, pc); | ||
27 | } | ||
28 | _evas_unwalk(e); | ||
29 | } | ||
30 | |||
31 | void | ||
32 | _evas_post_event_callback_free(Evas *e) | ||
33 | { | ||
34 | Evas_Post_Callback *pc; | ||
35 | |||
36 | EINA_LIST_FREE(e->post_events, pc) | ||
37 | { | ||
38 | EVAS_MEMPOOL_FREE(_mp_pc, pc); | ||
39 | } | ||
40 | _evas_unwalk(e); | ||
41 | } | ||
42 | |||
43 | void | ||
44 | evas_event_callback_list_post_free(Eina_Inlist **list) | ||
45 | { | ||
46 | Eina_Inlist *l; | ||
47 | |||
48 | /* MEM OK */ | ||
49 | for (l = *list; l;) | ||
50 | { | ||
51 | Evas_Func_Node *fn; | ||
52 | |||
53 | fn = (Evas_Func_Node *)l; | ||
54 | l = l->next; | ||
55 | if (fn->delete_me) | ||
56 | { | ||
57 | *list = eina_inlist_remove(*list, EINA_INLIST_GET(fn)); | ||
58 | EVAS_MEMPOOL_FREE(_mp_fn, fn); | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | |||
63 | static void | ||
64 | evas_object_event_callback_clear(Evas_Object *obj) | ||
65 | { | ||
66 | if (!obj->callbacks) return; | ||
67 | if (!obj->callbacks->deletions_waiting) return; | ||
68 | obj->callbacks->deletions_waiting = 0; | ||
69 | evas_event_callback_list_post_free(&obj->callbacks->callbacks); | ||
70 | if (!obj->callbacks->callbacks) | ||
71 | { | ||
72 | EVAS_MEMPOOL_FREE(_mp_cb, obj->callbacks); | ||
73 | obj->callbacks = NULL; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static void | ||
78 | evas_event_callback_clear(Evas *e) | ||
79 | { | ||
80 | if (!e->callbacks) return; | ||
81 | if (!e->callbacks->deletions_waiting) return; | ||
82 | e->callbacks->deletions_waiting = 0; | ||
83 | evas_event_callback_list_post_free(&e->callbacks->callbacks); | ||
84 | if (!e->callbacks->callbacks) | ||
85 | { | ||
86 | EVAS_MEMPOOL_FREE(_mp_cb, e->callbacks); | ||
87 | e->callbacks = NULL; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | void | ||
92 | evas_object_event_callback_all_del(Evas_Object *obj) | ||
93 | { | ||
94 | Evas_Func_Node *fn; | ||
95 | |||
96 | if (!obj->callbacks) return; | ||
97 | EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn) | ||
98 | fn->delete_me = 1; | ||
99 | } | ||
100 | |||
101 | void | ||
102 | evas_object_event_callback_cleanup(Evas_Object *obj) | ||
103 | { | ||
104 | /* MEM OK */ | ||
105 | if (!obj->callbacks) return; | ||
106 | evas_event_callback_list_post_free(&obj->callbacks->callbacks); | ||
107 | EVAS_MEMPOOL_FREE(_mp_cb, obj->callbacks); | ||
108 | obj->callbacks = NULL; | ||
109 | } | ||
110 | |||
111 | void | ||
112 | evas_event_callback_all_del(Evas *e) | ||
113 | { | ||
114 | Evas_Func_Node *fn; | ||
115 | |||
116 | if (!e->callbacks) return; | ||
117 | EINA_INLIST_FOREACH(e->callbacks->callbacks, fn) | ||
118 | fn->delete_me = 1; | ||
119 | } | ||
120 | |||
121 | void | ||
122 | evas_event_callback_cleanup(Evas *e) | ||
123 | { | ||
124 | /* MEM OK */ | ||
125 | if (!e->callbacks) return; | ||
126 | evas_event_callback_list_post_free(&e->callbacks->callbacks); | ||
127 | EVAS_MEMPOOL_FREE(_mp_cb, e->callbacks); | ||
128 | e->callbacks = NULL; | ||
129 | } | ||
130 | |||
131 | void | ||
132 | evas_event_callback_call(Evas *e, Evas_Callback_Type type, void *event_info) | ||
133 | { | ||
134 | Eina_Inlist **l_mod = NULL, *l; | ||
135 | |||
136 | _evas_walk(e); | ||
137 | if (e->callbacks) | ||
138 | { | ||
139 | l_mod = &e->callbacks->callbacks; | ||
140 | e->callbacks->walking_list++; | ||
141 | for (l = *l_mod; l; l = l->next) | ||
142 | { | ||
143 | Evas_Func_Node *fn; | ||
144 | |||
145 | fn = (Evas_Func_Node *)l; | ||
146 | if ((fn->type == type) && (!fn->delete_me)) | ||
147 | { | ||
148 | Evas_Event_Cb func = fn->func; | ||
149 | if (func) | ||
150 | func(fn->data, e, event_info); | ||
151 | } | ||
152 | if (e->delete_me) break; | ||
153 | } | ||
154 | e->callbacks->walking_list--; | ||
155 | if (!e->callbacks->walking_list) | ||
156 | { | ||
157 | evas_event_callback_clear(e); | ||
158 | l_mod = NULL; | ||
159 | } | ||
160 | } | ||
161 | _evas_unwalk(e); | ||
162 | } | ||
163 | |||
164 | void | ||
165 | evas_object_event_callback_call(Evas_Object *obj, Evas_Callback_Type type, void *event_info) | ||
166 | { | ||
167 | /* MEM OK */ | ||
168 | Eina_Inlist **l_mod = NULL, *l; | ||
169 | Evas_Button_Flags flags = EVAS_BUTTON_NONE; | ||
170 | Evas *e; | ||
171 | |||
172 | if ((obj->delete_me) || (!obj->layer)) return; | ||
173 | if ((obj->last_event == _evas_event_counter) && | ||
174 | (obj->last_event_type == type)) return; | ||
175 | obj->last_event = _evas_event_counter; | ||
176 | obj->last_event_type = type; | ||
177 | if (!(e = obj->layer->evas)) return; | ||
178 | |||
179 | _evas_walk(e); | ||
180 | if (obj->callbacks) | ||
181 | { | ||
182 | l_mod = &obj->callbacks->callbacks; | ||
183 | switch (type) | ||
184 | { | ||
185 | case EVAS_CALLBACK_MOUSE_DOWN: | ||
186 | { | ||
187 | Evas_Event_Mouse_Down *ev = event_info; | ||
188 | |||
189 | flags = ev->flags; | ||
190 | if (ev->flags & (EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK)) | ||
191 | { | ||
192 | if (obj->last_mouse_down_counter < (e->last_mouse_down_counter - 1)) | ||
193 | ev->flags &= ~(EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK); | ||
194 | } | ||
195 | obj->last_mouse_down_counter = e->last_mouse_down_counter; | ||
196 | break; | ||
197 | } | ||
198 | case EVAS_CALLBACK_MOUSE_UP: | ||
199 | { | ||
200 | Evas_Event_Mouse_Up *ev = event_info; | ||
201 | |||
202 | flags = ev->flags; | ||
203 | if (ev->flags & (EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK)) | ||
204 | { | ||
205 | if (obj->last_mouse_up_counter < (e->last_mouse_up_counter - 1)) | ||
206 | ev->flags &= ~(EVAS_BUTTON_DOUBLE_CLICK | EVAS_BUTTON_TRIPLE_CLICK); | ||
207 | } | ||
208 | obj->last_mouse_up_counter = e->last_mouse_up_counter; | ||
209 | break; | ||
210 | } | ||
211 | default: | ||
212 | break; | ||
213 | } | ||
214 | obj->callbacks->walking_list++; | ||
215 | for (l = *l_mod; l; l = l->next) | ||
216 | { | ||
217 | Evas_Func_Node *fn; | ||
218 | |||
219 | fn = (Evas_Func_Node *)l; | ||
220 | if ((fn->type == type) && (!fn->delete_me)) | ||
221 | { | ||
222 | Evas_Object_Event_Cb func = fn->func; | ||
223 | if (func) | ||
224 | func(fn->data, obj->layer->evas, obj, event_info); | ||
225 | } | ||
226 | if (obj->delete_me) break; | ||
227 | } | ||
228 | obj->callbacks->walking_list--; | ||
229 | if (!obj->callbacks->walking_list) | ||
230 | { | ||
231 | evas_object_event_callback_clear(obj); | ||
232 | l_mod = NULL; | ||
233 | } | ||
234 | |||
235 | if (type == EVAS_CALLBACK_MOUSE_DOWN) | ||
236 | { | ||
237 | Evas_Event_Mouse_Down *ev = event_info; | ||
238 | ev->flags = flags; | ||
239 | } | ||
240 | else if (type == EVAS_CALLBACK_MOUSE_UP) | ||
241 | { | ||
242 | Evas_Event_Mouse_Up *ev = event_info; | ||
243 | ev->flags = flags; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | if (!((obj->no_propagate) && (l_mod) && (*l_mod))) | ||
248 | { | ||
249 | if (!obj->no_propagate) | ||
250 | { | ||
251 | if ((obj->smart.parent) && (type != EVAS_CALLBACK_FREE) && | ||
252 | (type <= EVAS_CALLBACK_KEY_UP)) | ||
253 | evas_object_event_callback_call(obj->smart.parent, type, event_info); | ||
254 | } | ||
255 | } | ||
256 | _evas_unwalk(e); | ||
257 | } | ||
258 | |||
259 | static int | ||
260 | _callback_priority_cmp(const void *_a, const void *_b) | ||
261 | { | ||
262 | const Evas_Func_Node *a, *b; | ||
263 | a = EINA_INLIST_CONTAINER_GET(_a, Evas_Func_Node); | ||
264 | b = EINA_INLIST_CONTAINER_GET(_b, Evas_Func_Node); | ||
265 | if (a->priority < b->priority) | ||
266 | return -1; | ||
267 | else | ||
268 | return 1; | ||
269 | } | ||
270 | |||
271 | EAPI void | ||
272 | evas_object_event_callback_add(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data) | ||
273 | { | ||
274 | evas_object_event_callback_priority_add(obj, type, | ||
275 | EVAS_CALLBACK_PRIORITY_DEFAULT, func, data); | ||
276 | } | ||
277 | |||
278 | EAPI void | ||
279 | evas_object_event_callback_priority_add(Evas_Object *obj, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Object_Event_Cb func, const void *data) | ||
280 | { | ||
281 | /* MEM OK */ | ||
282 | Evas_Func_Node *fn; | ||
283 | |||
284 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
285 | return; | ||
286 | MAGIC_CHECK_END(); | ||
287 | |||
288 | if (!func) return; | ||
289 | |||
290 | if (!obj->callbacks) | ||
291 | { | ||
292 | EVAS_MEMPOOL_INIT(_mp_cb, "evas_callbacks", Evas_Callbacks, 512, ); | ||
293 | obj->callbacks = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Callbacks); | ||
294 | if (!obj->callbacks) return; | ||
295 | EVAS_MEMPOOL_PREP(_mp_cb, obj->callbacks, Evas_Callbacks); | ||
296 | } | ||
297 | |||
298 | EVAS_MEMPOOL_INIT(_mp_fn, "evas_func_node", Evas_Func_Node, 2048, ); | ||
299 | fn = EVAS_MEMPOOL_ALLOC(_mp_fn, Evas_Func_Node); | ||
300 | if (!fn) return; | ||
301 | EVAS_MEMPOOL_PREP(_mp_fn, fn, Evas_Func_Node); | ||
302 | fn->func = func; | ||
303 | fn->data = (void *)data; | ||
304 | fn->type = type; | ||
305 | fn->priority = priority; | ||
306 | |||
307 | obj->callbacks->callbacks = | ||
308 | eina_inlist_sorted_insert(obj->callbacks->callbacks, EINA_INLIST_GET(fn), | ||
309 | _callback_priority_cmp); | ||
310 | } | ||
311 | |||
312 | EAPI void * | ||
313 | evas_object_event_callback_del(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func) | ||
314 | { | ||
315 | /* MEM OK */ | ||
316 | Evas_Func_Node *fn; | ||
317 | |||
318 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
319 | return NULL; | ||
320 | MAGIC_CHECK_END(); | ||
321 | |||
322 | if (!func) return NULL; | ||
323 | |||
324 | if (!obj->callbacks) return NULL; | ||
325 | |||
326 | EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn) | ||
327 | { | ||
328 | if ((fn->func == func) && (fn->type == type) && (!fn->delete_me)) | ||
329 | { | ||
330 | void *tmp; | ||
331 | |||
332 | tmp = fn->data; | ||
333 | fn->delete_me = 1; | ||
334 | obj->callbacks->deletions_waiting = 1; | ||
335 | if (!obj->callbacks->walking_list) | ||
336 | evas_object_event_callback_clear(obj); | ||
337 | return tmp; | ||
338 | } | ||
339 | } | ||
340 | return NULL; | ||
341 | } | ||
342 | |||
343 | EAPI void * | ||
344 | evas_object_event_callback_del_full(Evas_Object *obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data) | ||
345 | { | ||
346 | /* MEM OK */ | ||
347 | Evas_Func_Node *fn; | ||
348 | |||
349 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
350 | return NULL; | ||
351 | MAGIC_CHECK_END(); | ||
352 | |||
353 | if (!func) return NULL; | ||
354 | |||
355 | if (!obj->callbacks) return NULL; | ||
356 | |||
357 | EINA_INLIST_FOREACH(obj->callbacks->callbacks, fn) | ||
358 | { | ||
359 | if ((fn->func == func) && (fn->type == type) && (fn->data == data) && (!fn->delete_me)) | ||
360 | { | ||
361 | void *tmp; | ||
362 | |||
363 | tmp = fn->data; | ||
364 | fn->delete_me = 1; | ||
365 | obj->callbacks->deletions_waiting = 1; | ||
366 | if (!obj->callbacks->walking_list) | ||
367 | evas_object_event_callback_clear(obj); | ||
368 | return tmp; | ||
369 | } | ||
370 | } | ||
371 | return NULL; | ||
372 | } | ||
373 | |||
374 | EAPI void | ||
375 | evas_event_callback_add(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data) | ||
376 | { | ||
377 | evas_event_callback_priority_add(e, type, EVAS_CALLBACK_PRIORITY_DEFAULT, | ||
378 | func, data); | ||
379 | } | ||
380 | |||
381 | EAPI void | ||
382 | evas_event_callback_priority_add(Evas *e, Evas_Callback_Type type, Evas_Callback_Priority priority, Evas_Event_Cb func, const void *data) | ||
383 | { | ||
384 | /* MEM OK */ | ||
385 | Evas_Func_Node *fn; | ||
386 | |||
387 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
388 | return; | ||
389 | MAGIC_CHECK_END(); | ||
390 | |||
391 | if (!func) return; | ||
392 | |||
393 | if (!e->callbacks) | ||
394 | { | ||
395 | EVAS_MEMPOOL_INIT(_mp_cb, "evas_callbacks", Evas_Callbacks, 512, ); | ||
396 | e->callbacks = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Callbacks); | ||
397 | if (!e->callbacks) return; | ||
398 | EVAS_MEMPOOL_PREP(_mp_cb, e->callbacks, Evas_Callbacks); | ||
399 | } | ||
400 | |||
401 | EVAS_MEMPOOL_INIT(_mp_fn, "evas_func_node", Evas_Func_Node, 2048, ); | ||
402 | fn = EVAS_MEMPOOL_ALLOC(_mp_fn, Evas_Func_Node); | ||
403 | if (!fn) return; | ||
404 | EVAS_MEMPOOL_PREP(_mp_fn, fn, Evas_Func_Node); | ||
405 | fn->func = func; | ||
406 | fn->data = (void *)data; | ||
407 | fn->type = type; | ||
408 | fn->priority = priority; | ||
409 | |||
410 | e->callbacks->callbacks = eina_inlist_sorted_insert(e->callbacks->callbacks, | ||
411 | EINA_INLIST_GET(fn), _callback_priority_cmp); | ||
412 | } | ||
413 | |||
414 | EAPI void * | ||
415 | evas_event_callback_del(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func) | ||
416 | { | ||
417 | /* MEM OK */ | ||
418 | Evas_Func_Node *fn; | ||
419 | |||
420 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
421 | return NULL; | ||
422 | MAGIC_CHECK_END(); | ||
423 | |||
424 | if (!func) return NULL; | ||
425 | |||
426 | if (!e->callbacks) return NULL; | ||
427 | |||
428 | EINA_INLIST_FOREACH(e->callbacks->callbacks, fn) | ||
429 | { | ||
430 | if ((fn->func == func) && (fn->type == type) && (!fn->delete_me)) | ||
431 | { | ||
432 | void *data; | ||
433 | |||
434 | data = fn->data; | ||
435 | fn->delete_me = 1; | ||
436 | e->callbacks->deletions_waiting = 1; | ||
437 | if (!e->callbacks->walking_list) | ||
438 | evas_event_callback_clear(e); | ||
439 | return data; | ||
440 | } | ||
441 | } | ||
442 | return NULL; | ||
443 | } | ||
444 | |||
445 | EAPI void * | ||
446 | evas_event_callback_del_full(Evas *e, Evas_Callback_Type type, Evas_Event_Cb func, const void *data) | ||
447 | { | ||
448 | /* MEM OK */ | ||
449 | Evas_Func_Node *fn; | ||
450 | |||
451 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
452 | return NULL; | ||
453 | MAGIC_CHECK_END(); | ||
454 | |||
455 | if (!func) return NULL; | ||
456 | |||
457 | if (!e->callbacks) return NULL; | ||
458 | |||
459 | EINA_INLIST_FOREACH(e->callbacks->callbacks, fn) | ||
460 | { | ||
461 | if ((fn->func == func) && (fn->type == type) && (fn->data == data) && (!fn->delete_me)) | ||
462 | { | ||
463 | void *tmp; | ||
464 | |||
465 | tmp = fn->data; | ||
466 | fn->delete_me = 1; | ||
467 | e->callbacks->deletions_waiting = 1; | ||
468 | if (!e->callbacks->walking_list) | ||
469 | evas_event_callback_clear(e); | ||
470 | return tmp; | ||
471 | } | ||
472 | } | ||
473 | return NULL; | ||
474 | } | ||
475 | |||
476 | EAPI void | ||
477 | evas_post_event_callback_push(Evas *e, Evas_Object_Event_Post_Cb func, const void *data) | ||
478 | { | ||
479 | Evas_Post_Callback *pc; | ||
480 | |||
481 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
482 | return; | ||
483 | MAGIC_CHECK_END(); | ||
484 | |||
485 | EVAS_MEMPOOL_INIT(_mp_pc, "evas_post_callback", Evas_Post_Callback, 64, ); | ||
486 | pc = EVAS_MEMPOOL_ALLOC(_mp_pc, Evas_Post_Callback); | ||
487 | if (!pc) return; | ||
488 | EVAS_MEMPOOL_PREP(_mp_pc, pc, Evas_Post_Callback); | ||
489 | if (e->delete_me) return; | ||
490 | |||
491 | pc->func = func; | ||
492 | pc->data = data; | ||
493 | e->post_events = eina_list_prepend(e->post_events, pc); | ||
494 | } | ||
495 | |||
496 | EAPI void | ||
497 | evas_post_event_callback_remove(Evas *e, Evas_Object_Event_Post_Cb func) | ||
498 | { | ||
499 | Evas_Post_Callback *pc; | ||
500 | Eina_List *l; | ||
501 | |||
502 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
503 | return; | ||
504 | MAGIC_CHECK_END(); | ||
505 | |||
506 | EINA_LIST_FOREACH(e->post_events, l, pc) | ||
507 | { | ||
508 | if (pc->func == func) | ||
509 | { | ||
510 | pc->delete_me = 1; | ||
511 | return; | ||
512 | } | ||
513 | } | ||
514 | } | ||
515 | |||
516 | EAPI void | ||
517 | evas_post_event_callback_remove_full(Evas *e, Evas_Object_Event_Post_Cb func, const void *data) | ||
518 | { | ||
519 | Evas_Post_Callback *pc; | ||
520 | Eina_List *l; | ||
521 | |||
522 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
523 | return; | ||
524 | MAGIC_CHECK_END(); | ||
525 | |||
526 | EINA_LIST_FOREACH(e->post_events, l, pc) | ||
527 | { | ||
528 | if ((pc->func == func) && (pc->data == data)) | ||
529 | { | ||
530 | pc->delete_me = 1; | ||
531 | return; | ||
532 | } | ||
533 | } | ||
534 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_clip.c b/libraries/evas/src/lib/canvas/evas_clip.c new file mode 100644 index 0000000..1ae2f73 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_clip.c | |||
@@ -0,0 +1,321 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | void | ||
5 | evas_object_clip_dirty(Evas_Object *obj) | ||
6 | { | ||
7 | Eina_List *l; | ||
8 | Evas_Object *data; | ||
9 | |||
10 | if (obj->cur.cache.clip.dirty) return ; | ||
11 | |||
12 | obj->cur.cache.clip.dirty = 1; | ||
13 | EINA_LIST_FOREACH(obj->clip.clipees, l, data) | ||
14 | evas_object_clip_dirty(data); | ||
15 | } | ||
16 | |||
17 | void | ||
18 | evas_object_recalc_clippees(Evas_Object *obj) | ||
19 | { | ||
20 | Eina_List *l; | ||
21 | Evas_Object *data; | ||
22 | |||
23 | if (obj->cur.cache.clip.dirty) | ||
24 | { | ||
25 | evas_object_clip_recalc(obj); | ||
26 | EINA_LIST_FOREACH(obj->clip.clipees, l, data) | ||
27 | evas_object_recalc_clippees(data); | ||
28 | } | ||
29 | } | ||
30 | |||
31 | int | ||
32 | evas_object_clippers_was_visible(Evas_Object *obj) | ||
33 | { | ||
34 | if (obj->prev.visible) | ||
35 | { | ||
36 | if (obj->prev.clipper) | ||
37 | return evas_object_clippers_is_visible(obj->prev.clipper); | ||
38 | return 1; | ||
39 | } | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | /* aaaaargh (pirate voice) ... notes! | ||
44 | * | ||
45 | * we have a big problem until now that's gone undetected... until yesterday. | ||
46 | * that problem involves clips and maps and smart objects. hooray! 3 of the | ||
47 | * more complex bits of evas - and maps and smart objects being one of the | ||
48 | * nastiest ones. | ||
49 | * | ||
50 | * what is the problem? when a clip crosses a map boundary. that is to say | ||
51 | * that when the clipper and clippee are not within the child tree of the | ||
52 | * mapped object. in this case "bad stuff" happens. basically as clips are | ||
53 | * then used to render objects, but they no longer apply as you'd expect as | ||
54 | * the map transfomr the objects to-be-clipped separately from the objects | ||
55 | * that clip them and this whole relationship is broken by maps. it somehow | ||
56 | * managed to not break with the advent of smart objects. lucky me... but | ||
57 | * maps killed it. now... what do we do? that is a good question. detect | ||
58 | * such a broken link and "turn off clipping" in that event - sure. but this | ||
59 | * isn't going to be cheap as ANY addition or deletion of a map to an object | ||
60 | * or any change in clipper of an object or any change in smart object | ||
61 | * membership needs to walk the obj tree both up and down from the changed | ||
62 | * object and probably walk entire object trees to find these and mark them. | ||
63 | * thats silly-expensive and i was about to fix it that way but it has since | ||
64 | * dawned on me that that is just going to kill performance in some critical | ||
65 | * areas like during object setup and manipulation, as well as teardown. | ||
66 | * | ||
67 | * aaaaagh! best for now is to document this as a "don't do it damnit!" thing | ||
68 | * and have the apps avoid it. but even then - how to do this? this is not | ||
69 | * easy. everywhere i turn so far i come up to either expensive operations, | ||
70 | * breaks in logic, or nasty re-work of apps or4 the whole concept of clipping, | ||
71 | * smart objects and maps... and that will have to wait for evas 2.0 | ||
72 | * | ||
73 | * the below does clip fixups etc. in the even a clip spans a map boundary. | ||
74 | * not pretty, but necessary. | ||
75 | */ | ||
76 | |||
77 | #define MAP_ACROSS 1 | ||
78 | static void | ||
79 | evas_object_child_map_across_mark(Evas_Object *obj, Evas_Object *map_obj, Eina_Bool force) | ||
80 | { | ||
81 | #ifdef MAP_ACROSS | ||
82 | if ((obj->cur.map_parent != map_obj) || force) | ||
83 | { | ||
84 | obj->cur.map_parent = map_obj; | ||
85 | obj->cur.cache.clip.dirty = 1; | ||
86 | evas_object_clip_recalc(obj); | ||
87 | if (obj->smart.smart) | ||
88 | { | ||
89 | Evas_Object *obj2; | ||
90 | |||
91 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2) | ||
92 | { | ||
93 | // if obj has its own map - skip it. already done | ||
94 | if ((obj2->cur.map) && (obj2->cur.usemap)) continue; | ||
95 | evas_object_child_map_across_mark(obj2, map_obj, force); | ||
96 | } | ||
97 | } | ||
98 | else if (obj->clip.clipees) | ||
99 | { | ||
100 | Eina_List *l; | ||
101 | Evas_Object *obj2; | ||
102 | |||
103 | EINA_LIST_FOREACH(obj->clip.clipees, l, obj2) | ||
104 | evas_object_child_map_across_mark(obj2, map_obj, force); | ||
105 | } | ||
106 | } | ||
107 | #endif | ||
108 | } | ||
109 | |||
110 | void | ||
111 | evas_object_clip_across_check(Evas_Object *obj) | ||
112 | { | ||
113 | #ifdef MAP_ACROSS | ||
114 | if (!obj->cur.clipper) return; | ||
115 | if (obj->cur.clipper->cur.map_parent != obj->cur.map_parent) | ||
116 | evas_object_child_map_across_mark(obj, obj->cur.map_parent, 1); | ||
117 | #endif | ||
118 | } | ||
119 | |||
120 | void | ||
121 | evas_object_clip_across_clippees_check(Evas_Object *obj) | ||
122 | { | ||
123 | #ifdef MAP_ACROSS | ||
124 | Eina_List *l; | ||
125 | Evas_Object *obj2; | ||
126 | |||
127 | if (!obj->clip.clipees) return; | ||
128 | // schloooooooooooow: | ||
129 | // evas_object_child_map_across_mark(obj, obj->cur.map_parent, 1); | ||
130 | // buggy: | ||
131 | evas_object_child_map_across_mark(obj, obj->cur.map_parent, 0); | ||
132 | if (obj->cur.cache.clip.dirty) | ||
133 | { | ||
134 | EINA_LIST_FOREACH(obj->clip.clipees, l, obj2) | ||
135 | evas_object_clip_across_clippees_check(obj2); | ||
136 | } | ||
137 | #endif | ||
138 | } | ||
139 | |||
140 | // this function is called on an object when map is enabled or disabled on it | ||
141 | // thus creating a "map boundary" at that point. | ||
142 | // | ||
143 | // FIXME: flip2 test broken in elm - might be show/hide of clips | ||
144 | void | ||
145 | evas_object_mapped_clip_across_mark(Evas_Object *obj) | ||
146 | { | ||
147 | #ifdef MAP_ACROSS | ||
148 | if ((obj->cur.map) && (obj->cur.usemap)) | ||
149 | evas_object_child_map_across_mark(obj, obj, 0); | ||
150 | else | ||
151 | { | ||
152 | if (obj->smart.parent) | ||
153 | evas_object_child_map_across_mark | ||
154 | (obj, obj->smart.parent->cur.map_parent, 0); | ||
155 | else | ||
156 | evas_object_child_map_across_mark(obj, NULL, 0); | ||
157 | } | ||
158 | #endif | ||
159 | } | ||
160 | |||
161 | /* public functions */ | ||
162 | extern const char *o_rect_type; | ||
163 | |||
164 | EAPI void | ||
165 | evas_object_clip_set(Evas_Object *obj, Evas_Object *clip) | ||
166 | { | ||
167 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
168 | return; | ||
169 | MAGIC_CHECK_END(); | ||
170 | if (!clip) | ||
171 | { | ||
172 | evas_object_clip_unset(obj); | ||
173 | return; | ||
174 | } | ||
175 | MAGIC_CHECK(clip, Evas_Object, MAGIC_OBJ); | ||
176 | return; | ||
177 | MAGIC_CHECK_END(); | ||
178 | if (obj->cur.clipper == clip) return; | ||
179 | if (obj == clip) return; | ||
180 | if (evas_object_intercept_call_clip_set(obj, clip)) return; | ||
181 | // illegal to set anything but a rect as a clip | ||
182 | if (clip->type != o_rect_type) | ||
183 | { | ||
184 | ERR("For now a clip on other object than a rectangle is disabled"); | ||
185 | return; | ||
186 | } | ||
187 | if (obj->smart.smart) | ||
188 | { | ||
189 | if (obj->smart.smart->smart_class->clip_set) | ||
190 | obj->smart.smart->smart_class->clip_set(obj, clip); | ||
191 | } | ||
192 | if (obj->cur.clipper) | ||
193 | { | ||
194 | /* unclip */ | ||
195 | obj->cur.clipper->clip.clipees = eina_list_remove(obj->cur.clipper->clip.clipees, obj); | ||
196 | if (!obj->cur.clipper->clip.clipees) | ||
197 | { | ||
198 | obj->cur.clipper->cur.have_clipees = 0; | ||
199 | if (obj->cur.clipper->cur.visible) | ||
200 | evas_damage_rectangle_add(obj->cur.clipper->layer->evas, | ||
201 | obj->cur.clipper->cur.geometry.x, | ||
202 | obj->cur.clipper->cur.geometry.y, | ||
203 | obj->cur.clipper->cur.geometry.w, | ||
204 | obj->cur.clipper->cur.geometry.h); | ||
205 | } | ||
206 | evas_object_change(obj->cur.clipper); | ||
207 | evas_object_change(obj); | ||
208 | obj->cur.clipper = NULL; | ||
209 | } | ||
210 | /* clip me */ | ||
211 | if ((!clip->clip.clipees) && (clip->cur.visible)) | ||
212 | { | ||
213 | /* Basically it just went invisible */ | ||
214 | clip->changed = 1; | ||
215 | clip->layer->evas->changed = 1; | ||
216 | evas_damage_rectangle_add(clip->layer->evas, | ||
217 | clip->cur.geometry.x, clip->cur.geometry.y, | ||
218 | clip->cur.geometry.w, clip->cur.geometry.h); | ||
219 | } | ||
220 | obj->cur.clipper = clip; | ||
221 | clip->clip.clipees = eina_list_append(clip->clip.clipees, obj); | ||
222 | if (clip->clip.clipees) clip->cur.have_clipees = 1; | ||
223 | |||
224 | /* If it's NOT a rectangle set the mask bits too */ | ||
225 | /* FIXME: Optmz ths chck */ | ||
226 | if (strcmp(evas_object_type_get(clip),"rectangle") == 0) | ||
227 | obj->cur.mask = NULL; | ||
228 | else | ||
229 | { | ||
230 | void *engdata; | ||
231 | obj->cur.mask = clip; | ||
232 | engdata = clip->func->engine_data_get(clip); | ||
233 | /* FIXME: Images only */ | ||
234 | clip->layer->evas->engine.func->image_mask_create( | ||
235 | clip->layer->evas->engine.data.output, | ||
236 | engdata); | ||
237 | } | ||
238 | evas_object_change(clip); | ||
239 | evas_object_change(obj); | ||
240 | evas_object_clip_dirty(obj); | ||
241 | evas_object_recalc_clippees(obj); | ||
242 | if ((!obj->smart.smart) && | ||
243 | (!((obj->cur.map) && (obj->cur.usemap)))) | ||
244 | { | ||
245 | if (evas_object_is_in_output_rect(obj, | ||
246 | obj->layer->evas->pointer.x, | ||
247 | obj->layer->evas->pointer.y, 1, 1)) | ||
248 | evas_event_feed_mouse_move(obj->layer->evas, | ||
249 | obj->layer->evas->pointer.x, | ||
250 | obj->layer->evas->pointer.y, | ||
251 | obj->layer->evas->last_timestamp, | ||
252 | NULL); | ||
253 | } | ||
254 | evas_object_clip_across_check(obj); | ||
255 | } | ||
256 | |||
257 | EAPI Evas_Object * | ||
258 | evas_object_clip_get(const Evas_Object *obj) | ||
259 | { | ||
260 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
261 | return NULL; | ||
262 | MAGIC_CHECK_END(); | ||
263 | return obj->cur.clipper; | ||
264 | } | ||
265 | |||
266 | EAPI void | ||
267 | evas_object_clip_unset(Evas_Object *obj) | ||
268 | { | ||
269 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
270 | return; | ||
271 | MAGIC_CHECK_END(); | ||
272 | if (!obj->cur.clipper) return; | ||
273 | /* unclip */ | ||
274 | if (evas_object_intercept_call_clip_unset(obj)) return; | ||
275 | if (obj->smart.smart) | ||
276 | { | ||
277 | if (obj->smart.smart->smart_class->clip_unset) | ||
278 | obj->smart.smart->smart_class->clip_unset(obj); | ||
279 | } | ||
280 | if (obj->cur.clipper) | ||
281 | { | ||
282 | obj->cur.clipper->clip.clipees = eina_list_remove(obj->cur.clipper->clip.clipees, obj); | ||
283 | if (!obj->cur.clipper->clip.clipees) | ||
284 | { | ||
285 | obj->cur.clipper->cur.have_clipees = 0; | ||
286 | if (obj->cur.clipper->cur.visible) | ||
287 | evas_damage_rectangle_add(obj->cur.clipper->layer->evas, | ||
288 | obj->cur.clipper->cur.geometry.x, | ||
289 | obj->cur.clipper->cur.geometry.y, | ||
290 | obj->cur.clipper->cur.geometry.w, | ||
291 | obj->cur.clipper->cur.geometry.h); | ||
292 | } | ||
293 | evas_object_change(obj->cur.clipper); | ||
294 | } | ||
295 | obj->cur.clipper = NULL; | ||
296 | evas_object_change(obj); | ||
297 | evas_object_clip_dirty(obj); | ||
298 | evas_object_recalc_clippees(obj); | ||
299 | if ((!obj->smart.smart) && | ||
300 | (!((obj->cur.map) && (obj->cur.usemap)))) | ||
301 | { | ||
302 | if (evas_object_is_in_output_rect(obj, | ||
303 | obj->layer->evas->pointer.x, | ||
304 | obj->layer->evas->pointer.y, 1, 1)) | ||
305 | evas_event_feed_mouse_move(obj->layer->evas, | ||
306 | obj->layer->evas->pointer.x, | ||
307 | obj->layer->evas->pointer.y, | ||
308 | obj->layer->evas->last_timestamp, | ||
309 | NULL); | ||
310 | } | ||
311 | evas_object_clip_across_check(obj); | ||
312 | } | ||
313 | |||
314 | EAPI const Eina_List * | ||
315 | evas_object_clipees_get(const Evas_Object *obj) | ||
316 | { | ||
317 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
318 | return NULL; | ||
319 | MAGIC_CHECK_END(); | ||
320 | return obj->clip.clipees; | ||
321 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_data.c b/libraries/evas/src/lib/canvas/evas_data.c new file mode 100644 index 0000000..3ac9d63 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_data.c | |||
@@ -0,0 +1,72 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | |||
5 | EAPI void | ||
6 | evas_object_data_set(Evas_Object *obj, const char *key, const void *data) | ||
7 | { | ||
8 | Evas_Data_Node *node; | ||
9 | |||
10 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
11 | return; | ||
12 | MAGIC_CHECK_END(); | ||
13 | if (!key) return; | ||
14 | |||
15 | evas_object_data_del(obj, key); | ||
16 | if (!data) return; | ||
17 | node = malloc(sizeof(Evas_Data_Node) + strlen(key) + 1); | ||
18 | node->key = (char *)node + sizeof(Evas_Data_Node); | ||
19 | strcpy(node->key, key); | ||
20 | node->data = (void *)data; | ||
21 | obj->data.elements = eina_list_prepend(obj->data.elements, node); | ||
22 | } | ||
23 | |||
24 | EAPI void * | ||
25 | evas_object_data_get(const Evas_Object *obj, const char *key) | ||
26 | { | ||
27 | Eina_List *l; | ||
28 | Evas_Data_Node *node; | ||
29 | |||
30 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
31 | return NULL; | ||
32 | MAGIC_CHECK_END(); | ||
33 | if (!key) return NULL; | ||
34 | |||
35 | EINA_LIST_FOREACH(obj->data.elements, l, node) | ||
36 | { | ||
37 | if (!strcmp(node->key, key)) | ||
38 | { | ||
39 | Eina_List *lst; | ||
40 | lst = obj->data.elements; | ||
41 | lst = eina_list_promote_list(lst, l); | ||
42 | ((Evas_Object *)obj)->data.elements = lst; | ||
43 | return node->data; | ||
44 | } | ||
45 | } | ||
46 | return NULL; | ||
47 | } | ||
48 | |||
49 | EAPI void * | ||
50 | evas_object_data_del(Evas_Object *obj, const char *key) | ||
51 | { | ||
52 | Eina_List *l; | ||
53 | Evas_Data_Node *node; | ||
54 | |||
55 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
56 | return NULL; | ||
57 | MAGIC_CHECK_END(); | ||
58 | if (!key) return NULL; | ||
59 | EINA_LIST_FOREACH(obj->data.elements, l, node) | ||
60 | { | ||
61 | if (!strcmp(node->key, key)) | ||
62 | { | ||
63 | void *data; | ||
64 | |||
65 | data = node->data; | ||
66 | obj->data.elements = eina_list_remove_list(obj->data.elements, l); | ||
67 | free(node); | ||
68 | return data; | ||
69 | } | ||
70 | } | ||
71 | return NULL; | ||
72 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_events.c b/libraries/evas/src/lib/canvas/evas_events.c new file mode 100644 index 0000000..99ecf8c --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_events.c | |||
@@ -0,0 +1,1602 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | static void | ||
5 | _evas_event_havemap_adjust(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Eina_Bool mouse_grabbed) | ||
6 | { | ||
7 | if (obj->smart.parent) | ||
8 | _evas_event_havemap_adjust(obj->smart.parent, x, y, mouse_grabbed); | ||
9 | |||
10 | if ((!obj->cur.usemap) || (!obj->cur.map) || (!obj->cur.map->count == 4)) | ||
11 | return; | ||
12 | |||
13 | evas_map_coords_get(obj->cur.map, *x, *y, x, y, mouse_grabbed); | ||
14 | *x += obj->cur.geometry.x; | ||
15 | *y += obj->cur.geometry.y; | ||
16 | } | ||
17 | |||
18 | static Eina_List * | ||
19 | _evas_event_object_list_in_get(Evas *e, Eina_List *in, | ||
20 | const Eina_Inlist *list, Evas_Object *stop, | ||
21 | int x, int y, int *no_rep) | ||
22 | { | ||
23 | Evas_Object *obj; | ||
24 | if (!list) return in; | ||
25 | EINA_INLIST_REVERSE_FOREACH(list, obj) | ||
26 | { | ||
27 | if (obj == stop) | ||
28 | { | ||
29 | *no_rep = 1; | ||
30 | return in; | ||
31 | } | ||
32 | if (evas_event_passes_through(obj)) continue; | ||
33 | if ((obj->cur.visible) && (obj->delete_me == 0) && | ||
34 | (!obj->clip.clipees) && | ||
35 | (evas_object_clippers_is_visible(obj))) | ||
36 | { | ||
37 | if (obj->smart.smart) | ||
38 | { | ||
39 | int norep = 0; | ||
40 | int inside; | ||
41 | |||
42 | if (((obj->cur.usemap) && (obj->cur.map) && (obj->cur.map->count == 4))) | ||
43 | { | ||
44 | inside = evas_object_is_in_output_rect(obj, x, y, 1, 1); | ||
45 | if (inside) | ||
46 | { | ||
47 | if (!evas_map_coords_get(obj->cur.map, x, y, | ||
48 | &(obj->cur.map->mx), | ||
49 | &(obj->cur.map->my), 0)) | ||
50 | { | ||
51 | inside = 0; | ||
52 | } | ||
53 | else | ||
54 | { | ||
55 | in = _evas_event_object_list_in_get | ||
56 | (e, in, | ||
57 | evas_object_smart_members_get_direct(obj), | ||
58 | stop, | ||
59 | obj->cur.geometry.x + obj->cur.map->mx, | ||
60 | obj->cur.geometry.y + obj->cur.map->my, &norep); | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | else | ||
65 | { | ||
66 | in = _evas_event_object_list_in_get | ||
67 | (e, in, evas_object_smart_members_get_direct(obj), | ||
68 | stop, x, y, &norep); | ||
69 | } | ||
70 | if (norep) | ||
71 | { | ||
72 | if (!obj->repeat_events) *no_rep = 1; | ||
73 | return in; | ||
74 | } | ||
75 | } | ||
76 | else | ||
77 | { | ||
78 | int inside = evas_object_is_in_output_rect(obj, x, y, 1, 1); | ||
79 | |||
80 | if (((obj->cur.usemap) && (obj->cur.map) && (obj->cur.map->count == 4))) | ||
81 | { | ||
82 | if ((inside) && (!evas_map_coords_get(obj->cur.map, x, y, | ||
83 | &(obj->cur.map->mx), | ||
84 | &(obj->cur.map->my), 0))) | ||
85 | { | ||
86 | inside = 0; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | if (inside && ((!obj->precise_is_inside) || | ||
91 | (evas_object_is_inside(obj, x, y)))) | ||
92 | { | ||
93 | if (!evas_event_freezes_through(obj)) | ||
94 | in = eina_list_append(in, obj); | ||
95 | if (!obj->repeat_events) | ||
96 | { | ||
97 | *no_rep = 1; | ||
98 | return in; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | *no_rep = 0; | ||
105 | return in; | ||
106 | } | ||
107 | |||
108 | Eina_List * | ||
109 | evas_event_objects_event_list(Evas *e, Evas_Object *stop, int x, int y) | ||
110 | { | ||
111 | Evas_Layer *lay; | ||
112 | Eina_List *in = NULL; | ||
113 | |||
114 | if ((!e->layers) || (e->events_frozen > 0)) return NULL; | ||
115 | EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay) | ||
116 | { | ||
117 | int norep = 0; | ||
118 | in = _evas_event_object_list_in_get(e, in, | ||
119 | EINA_INLIST_GET(lay->objects), | ||
120 | stop, x, y, &norep); | ||
121 | if (norep) return in; | ||
122 | } | ||
123 | return in; | ||
124 | } | ||
125 | |||
126 | static Eina_List * | ||
127 | evas_event_list_copy(Eina_List *list) | ||
128 | { | ||
129 | Eina_List *l, *new_l = NULL; | ||
130 | const void *data; | ||
131 | |||
132 | EINA_LIST_FOREACH(list, l, data) | ||
133 | new_l = eina_list_append(new_l, data); | ||
134 | return new_l; | ||
135 | } | ||
136 | /* public functions */ | ||
137 | |||
138 | EAPI void | ||
139 | evas_event_freeze(Evas *e) | ||
140 | { | ||
141 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
142 | return; | ||
143 | MAGIC_CHECK_END(); | ||
144 | e->events_frozen++; | ||
145 | } | ||
146 | |||
147 | EAPI void | ||
148 | evas_event_thaw(Evas *e) | ||
149 | { | ||
150 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
151 | return; | ||
152 | MAGIC_CHECK_END(); | ||
153 | e->events_frozen--; | ||
154 | if (e->events_frozen == 0) | ||
155 | { | ||
156 | Evas_Layer *lay; | ||
157 | |||
158 | EINA_INLIST_FOREACH((EINA_INLIST_GET(e->layers)), lay) | ||
159 | { | ||
160 | Evas_Object *obj; | ||
161 | |||
162 | EINA_INLIST_FOREACH(lay->objects, obj) | ||
163 | { | ||
164 | evas_object_clip_recalc(obj); | ||
165 | evas_object_recalc_clippees(obj); | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | if (e->events_frozen < 0) | ||
170 | evas_debug_generic(" Thaw of events when already thawed!!!\n"); | ||
171 | } | ||
172 | |||
173 | EAPI int | ||
174 | evas_event_freeze_get(const Evas *e) | ||
175 | { | ||
176 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
177 | return 0; | ||
178 | MAGIC_CHECK_END(); | ||
179 | return e->events_frozen; | ||
180 | } | ||
181 | |||
182 | EAPI void | ||
183 | evas_event_thaw_eval(Evas *e) | ||
184 | { | ||
185 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
186 | return; | ||
187 | MAGIC_CHECK_END(); | ||
188 | if (e->events_frozen != 0) return; | ||
189 | |||
190 | evas_event_feed_mouse_move(e, e->pointer.x, e->pointer.y, | ||
191 | e->last_timestamp, NULL); | ||
192 | } | ||
193 | |||
194 | EAPI void | ||
195 | evas_event_feed_mouse_down(Evas *e, int b, Evas_Button_Flags flags, unsigned int timestamp, const void *data) | ||
196 | { | ||
197 | Eina_List *l, *copy; | ||
198 | Evas_Event_Mouse_Down ev; | ||
199 | Evas_Object *obj; | ||
200 | |||
201 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
202 | return; | ||
203 | MAGIC_CHECK_END(); | ||
204 | |||
205 | if ((b < 1) || (b > 32)) return; | ||
206 | |||
207 | e->pointer.button |= (1 << (b - 1)); | ||
208 | |||
209 | if (e->events_frozen > 0) return; | ||
210 | e->last_timestamp = timestamp; | ||
211 | |||
212 | _evas_object_event_new(); | ||
213 | |||
214 | ev.button = b; | ||
215 | ev.output.x = e->pointer.x; | ||
216 | ev.output.y = e->pointer.y; | ||
217 | ev.canvas.x = e->pointer.x; | ||
218 | ev.canvas.y = e->pointer.y; | ||
219 | ev.data = (void *)data; | ||
220 | ev.modifiers = &(e->modifiers); | ||
221 | ev.locks = &(e->locks); | ||
222 | ev.flags = flags; | ||
223 | ev.timestamp = timestamp; | ||
224 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
225 | |||
226 | _evas_walk(e); | ||
227 | /* append new touch point to the touch point list */ | ||
228 | _evas_touch_point_append(e, 0, e->pointer.x, e->pointer.y); | ||
229 | /* If this is the first finger down, i.e no other fingers pressed, | ||
230 | * get a new event list, otherwise, keep the current grabbed list. */ | ||
231 | if (e->pointer.mouse_grabbed == 0) | ||
232 | { | ||
233 | Eina_List *ins = evas_event_objects_event_list(e, | ||
234 | NULL, | ||
235 | e->pointer.x, | ||
236 | e->pointer.y); | ||
237 | /* free our old list of ins */ | ||
238 | e->pointer.object.in = eina_list_free(e->pointer.object.in); | ||
239 | /* and set up the new one */ | ||
240 | e->pointer.object.in = ins; | ||
241 | } | ||
242 | copy = evas_event_list_copy(e->pointer.object.in); | ||
243 | EINA_LIST_FOREACH(copy, l, obj) | ||
244 | { | ||
245 | if (obj->pointer_mode != EVAS_OBJECT_POINTER_MODE_NOGRAB) | ||
246 | { | ||
247 | obj->mouse_grabbed++; | ||
248 | e->pointer.mouse_grabbed++; | ||
249 | } | ||
250 | } | ||
251 | EINA_LIST_FOREACH(copy, l, obj) | ||
252 | { | ||
253 | if (obj->delete_me) continue; | ||
254 | ev.canvas.x = e->pointer.x; | ||
255 | ev.canvas.y = e->pointer.y; | ||
256 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
257 | |||
258 | if (e->events_frozen <= 0) | ||
259 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_DOWN, &ev); | ||
260 | if (e->delete_me) break; | ||
261 | } | ||
262 | if (copy) eina_list_free(copy); | ||
263 | e->last_mouse_down_counter++; | ||
264 | _evas_post_event_callback_call(e); | ||
265 | /* update touch point's state to EVAS_TOUCH_POINT_STILL */ | ||
266 | _evas_touch_point_update(e, 0, e->pointer.x, e->pointer.y, EVAS_TOUCH_POINT_STILL); | ||
267 | _evas_unwalk(e); | ||
268 | } | ||
269 | |||
270 | static int | ||
271 | _post_up_handle(Evas *e, unsigned int timestamp, const void *data) | ||
272 | { | ||
273 | Eina_List *l, *copy, *ins, *ll; | ||
274 | Evas_Event_Mouse_Out ev; | ||
275 | Evas_Object *obj; | ||
276 | int post_called = 0; | ||
277 | |||
278 | _evas_object_event_new(); | ||
279 | |||
280 | ev.buttons = e->pointer.button; | ||
281 | ev.output.x = e->pointer.x; | ||
282 | ev.output.y = e->pointer.y; | ||
283 | ev.canvas.x = e->pointer.x; | ||
284 | ev.canvas.y = e->pointer.y; | ||
285 | ev.data = (void *)data; | ||
286 | ev.modifiers = &(e->modifiers); | ||
287 | ev.locks = &(e->locks); | ||
288 | ev.timestamp = timestamp; | ||
289 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
290 | |||
291 | /* get new list of ins */ | ||
292 | ins = evas_event_objects_event_list(e, NULL, e->pointer.x, e->pointer.y); | ||
293 | /* go thru old list of in objects */ | ||
294 | copy = evas_event_list_copy(e->pointer.object.in); | ||
295 | EINA_LIST_FOREACH(copy, ll, obj) | ||
296 | { | ||
297 | ev.canvas.x = e->pointer.x; | ||
298 | ev.canvas.y = e->pointer.y; | ||
299 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
300 | if ((!eina_list_data_find(ins, obj)) || | ||
301 | (!e->pointer.inside)) | ||
302 | { | ||
303 | if (obj->mouse_in) | ||
304 | { | ||
305 | obj->mouse_in = 0; | ||
306 | if (e->events_frozen <= 0) | ||
307 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev); | ||
308 | } | ||
309 | } | ||
310 | if (e->delete_me) break; | ||
311 | } | ||
312 | _evas_post_event_callback_call(e); | ||
313 | |||
314 | if (copy) copy = eina_list_free(copy); | ||
315 | if (e->pointer.inside) | ||
316 | { | ||
317 | Evas_Event_Mouse_In ev_in; | ||
318 | Evas_Object *obj_itr; | ||
319 | |||
320 | _evas_object_event_new(); | ||
321 | |||
322 | ev_in.buttons = e->pointer.button; | ||
323 | ev_in.output.x = e->pointer.x; | ||
324 | ev_in.output.y = e->pointer.y; | ||
325 | ev_in.canvas.x = e->pointer.x; | ||
326 | ev_in.canvas.y = e->pointer.y; | ||
327 | ev_in.data = (void *)data; | ||
328 | ev_in.modifiers = &(e->modifiers); | ||
329 | ev_in.locks = &(e->locks); | ||
330 | ev_in.timestamp = timestamp; | ||
331 | ev_in.event_flags = EVAS_EVENT_FLAG_NONE; | ||
332 | |||
333 | EINA_LIST_FOREACH(ins, l, obj_itr) | ||
334 | { | ||
335 | ev_in.canvas.x = e->pointer.x; | ||
336 | ev_in.canvas.y = e->pointer.y; | ||
337 | _evas_event_havemap_adjust(obj_itr, &ev_in.canvas.x, &ev_in.canvas.y, obj_itr->mouse_grabbed); | ||
338 | if (!eina_list_data_find(e->pointer.object.in, obj_itr)) | ||
339 | { | ||
340 | if (!obj_itr->mouse_in) | ||
341 | { | ||
342 | obj_itr->mouse_in = 1; | ||
343 | if (e->events_frozen <= 0) | ||
344 | evas_object_event_callback_call(obj_itr, EVAS_CALLBACK_MOUSE_IN, &ev_in); | ||
345 | } | ||
346 | } | ||
347 | if (e->delete_me) break; | ||
348 | } | ||
349 | post_called = 1; | ||
350 | _evas_post_event_callback_call(e); | ||
351 | } | ||
352 | else | ||
353 | { | ||
354 | ins = eina_list_free(ins); | ||
355 | } | ||
356 | |||
357 | if (e->pointer.mouse_grabbed == 0) | ||
358 | { | ||
359 | /* free our old list of ins */ | ||
360 | eina_list_free(e->pointer.object.in); | ||
361 | /* and set up the new one */ | ||
362 | e->pointer.object.in = ins; | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | /* free our cur ins */ | ||
367 | eina_list_free(ins); | ||
368 | } | ||
369 | if (e->pointer.inside) | ||
370 | evas_event_feed_mouse_move(e, e->pointer.x, e->pointer.y, timestamp, data); | ||
371 | return post_called; | ||
372 | } | ||
373 | |||
374 | EAPI void | ||
375 | evas_event_feed_mouse_up(Evas *e, int b, Evas_Button_Flags flags, unsigned int timestamp, const void *data) | ||
376 | { | ||
377 | Eina_List *l, *copy; | ||
378 | |||
379 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
380 | return; | ||
381 | MAGIC_CHECK_END(); | ||
382 | |||
383 | if ((b < 1) || (b > 32)) return; | ||
384 | |||
385 | e->pointer.button &= ~(1 << (b - 1)); | ||
386 | |||
387 | if (e->events_frozen > 0) return; | ||
388 | e->last_timestamp = timestamp; | ||
389 | |||
390 | { | ||
391 | Evas_Event_Mouse_Up ev; | ||
392 | Evas_Object *obj; | ||
393 | |||
394 | _evas_object_event_new(); | ||
395 | |||
396 | ev.button = b; | ||
397 | ev.output.x = e->pointer.x; | ||
398 | ev.output.y = e->pointer.y; | ||
399 | ev.canvas.x = e->pointer.x; | ||
400 | ev.canvas.y = e->pointer.y; | ||
401 | ev.data = (void *)data; | ||
402 | ev.modifiers = &(e->modifiers); | ||
403 | ev.locks = &(e->locks); | ||
404 | ev.flags = flags; | ||
405 | ev.timestamp = timestamp; | ||
406 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
407 | |||
408 | _evas_walk(e); | ||
409 | /* update released touch point */ | ||
410 | _evas_touch_point_update(e, 0, e->pointer.x, e->pointer.y, EVAS_TOUCH_POINT_UP); | ||
411 | copy = evas_event_list_copy(e->pointer.object.in); | ||
412 | EINA_LIST_FOREACH(copy, l, obj) | ||
413 | { | ||
414 | ev.canvas.x = e->pointer.x; | ||
415 | ev.canvas.y = e->pointer.y; | ||
416 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
417 | if ((obj->pointer_mode != EVAS_OBJECT_POINTER_MODE_NOGRAB) && | ||
418 | (obj->mouse_grabbed > 0)) | ||
419 | { | ||
420 | obj->mouse_grabbed--; | ||
421 | e->pointer.mouse_grabbed--; | ||
422 | } | ||
423 | if (!obj->delete_me) | ||
424 | { | ||
425 | if (e->events_frozen <= 0) | ||
426 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_UP, &ev); | ||
427 | } | ||
428 | if (e->delete_me) break; | ||
429 | } | ||
430 | if (copy) copy = eina_list_free(copy); | ||
431 | e->last_mouse_up_counter++; | ||
432 | _evas_post_event_callback_call(e); | ||
433 | } | ||
434 | |||
435 | if (e->pointer.mouse_grabbed == 0) | ||
436 | { | ||
437 | _post_up_handle(e, timestamp, data); | ||
438 | } | ||
439 | |||
440 | if (e->pointer.mouse_grabbed < 0) | ||
441 | { | ||
442 | ERR("BUG? e->pointer.mouse_grabbed (=%d) < 0!", | ||
443 | e->pointer.mouse_grabbed); | ||
444 | } | ||
445 | /* remove released touch point from the touch point list */ | ||
446 | _evas_touch_point_remove(e, 0); | ||
447 | |||
448 | _evas_unwalk(e); | ||
449 | } | ||
450 | |||
451 | EAPI void | ||
452 | evas_event_feed_mouse_cancel(Evas *e, unsigned int timestamp, const void *data) | ||
453 | { | ||
454 | int i; | ||
455 | |||
456 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
457 | return; | ||
458 | MAGIC_CHECK_END(); | ||
459 | |||
460 | if (e->events_frozen > 0) return; | ||
461 | |||
462 | _evas_walk(e); | ||
463 | for (i = 0; i < 32; i++) | ||
464 | { | ||
465 | if ((e->pointer.button & (1 << i))) | ||
466 | evas_event_feed_mouse_up(e, i + 1, 0, timestamp, data); | ||
467 | } | ||
468 | _evas_unwalk(e); | ||
469 | } | ||
470 | |||
471 | EAPI void | ||
472 | evas_event_feed_mouse_wheel(Evas *e, int direction, int z, unsigned int timestamp, const void *data) | ||
473 | { | ||
474 | Eina_List *l, *copy; | ||
475 | Evas_Event_Mouse_Wheel ev; | ||
476 | Evas_Object *obj; | ||
477 | |||
478 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
479 | return; | ||
480 | MAGIC_CHECK_END(); | ||
481 | |||
482 | if (e->events_frozen > 0) return; | ||
483 | e->last_timestamp = timestamp; | ||
484 | |||
485 | _evas_object_event_new(); | ||
486 | |||
487 | ev.direction = direction; | ||
488 | ev.z = z; | ||
489 | ev.output.x = e->pointer.x; | ||
490 | ev.output.y = e->pointer.y; | ||
491 | ev.canvas.x = e->pointer.x; | ||
492 | ev.canvas.y = e->pointer.y; | ||
493 | ev.data = (void *) data; | ||
494 | ev.modifiers = &(e->modifiers); | ||
495 | ev.locks = &(e->locks); | ||
496 | ev.timestamp = timestamp; | ||
497 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
498 | |||
499 | _evas_walk(e); | ||
500 | copy = evas_event_list_copy(e->pointer.object.in); | ||
501 | |||
502 | EINA_LIST_FOREACH(copy, l, obj) | ||
503 | { | ||
504 | ev.canvas.x = e->pointer.x; | ||
505 | ev.canvas.y = e->pointer.y; | ||
506 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
507 | if ((e->events_frozen <= 0) && !evas_event_freezes_through(obj)) | ||
508 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_WHEEL, &ev); | ||
509 | if (e->delete_me) break; | ||
510 | } | ||
511 | if (copy) copy = eina_list_free(copy); | ||
512 | _evas_post_event_callback_call(e); | ||
513 | |||
514 | _evas_unwalk(e); | ||
515 | } | ||
516 | |||
517 | EAPI void | ||
518 | evas_event_feed_mouse_move(Evas *e, int x, int y, unsigned int timestamp, const void *data) | ||
519 | { | ||
520 | int px, py; | ||
521 | //// Evas_Coord pcx, pcy; | ||
522 | |||
523 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
524 | return; | ||
525 | MAGIC_CHECK_END(); | ||
526 | |||
527 | px = e->pointer.x; | ||
528 | py = e->pointer.y; | ||
529 | //// pcx = e->pointer.canvas_x; | ||
530 | //// pcy = e->pointer.canvas_y; | ||
531 | |||
532 | if (e->events_frozen > 0) return; | ||
533 | e->last_timestamp = timestamp; | ||
534 | |||
535 | e->pointer.x = x; | ||
536 | e->pointer.y = y; | ||
537 | //// e->pointer.canvas_x = x; | ||
538 | //// e->pointer.canvas_y = y; | ||
539 | //// e->pointer.canvas_x = evas_coord_screen_x_to_world(e, x); | ||
540 | //// e->pointer.canvas_y = evas_coord_screen_y_to_world(e, y); | ||
541 | if ((!e->pointer.inside) && (e->pointer.mouse_grabbed == 0)) return; | ||
542 | _evas_walk(e); | ||
543 | /* update moved touch point */ | ||
544 | if ((px != x) || (py != y)) | ||
545 | _evas_touch_point_update(e, 0, e->pointer.x, e->pointer.y, EVAS_TOUCH_POINT_MOVE); | ||
546 | /* if our mouse button is grabbed to any objects */ | ||
547 | if (e->pointer.mouse_grabbed > 0) | ||
548 | { | ||
549 | /* go thru old list of in objects */ | ||
550 | Eina_List *outs = NULL; | ||
551 | Eina_List *l, *copy; | ||
552 | |||
553 | { | ||
554 | Evas_Event_Mouse_Move ev; | ||
555 | Evas_Object *obj; | ||
556 | |||
557 | _evas_object_event_new(); | ||
558 | |||
559 | ev.buttons = e->pointer.button; | ||
560 | ev.cur.output.x = e->pointer.x; | ||
561 | ev.cur.output.y = e->pointer.y; | ||
562 | ev.cur.canvas.x = e->pointer.x; | ||
563 | ev.cur.canvas.y = e->pointer.y; | ||
564 | ev.prev.output.x = px; | ||
565 | ev.prev.output.y = py; | ||
566 | ev.prev.canvas.x = px; | ||
567 | ev.prev.canvas.y = py; | ||
568 | ev.data = (void *)data; | ||
569 | ev.modifiers = &(e->modifiers); | ||
570 | ev.locks = &(e->locks); | ||
571 | ev.timestamp = timestamp; | ||
572 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
573 | copy = evas_event_list_copy(e->pointer.object.in); | ||
574 | EINA_LIST_FOREACH(copy, l, obj) | ||
575 | { | ||
576 | ev.cur.canvas.x = e->pointer.x; | ||
577 | ev.cur.canvas.y = e->pointer.y; | ||
578 | _evas_event_havemap_adjust(obj, &ev.cur.canvas.x, | ||
579 | &ev.cur.canvas.y, | ||
580 | obj->mouse_grabbed); | ||
581 | if ((e->events_frozen <= 0) && | ||
582 | (evas_object_clippers_is_visible(obj) || | ||
583 | obj->mouse_grabbed) && | ||
584 | (!evas_event_passes_through(obj)) && | ||
585 | (!evas_event_freezes_through(obj)) && | ||
586 | (!obj->clip.clipees)) | ||
587 | { | ||
588 | if ((px != x) || (py != y)) | ||
589 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_MOVE, &ev); | ||
590 | } | ||
591 | else | ||
592 | outs = eina_list_append(outs, obj); | ||
593 | if (e->delete_me) break; | ||
594 | } | ||
595 | _evas_post_event_callback_call(e); | ||
596 | } | ||
597 | { | ||
598 | Evas_Event_Mouse_Out ev; | ||
599 | |||
600 | _evas_object_event_new(); | ||
601 | |||
602 | ev.buttons = e->pointer.button; | ||
603 | ev.output.x = e->pointer.x; | ||
604 | ev.output.y = e->pointer.y; | ||
605 | ev.canvas.x = e->pointer.x; | ||
606 | ev.canvas.y = e->pointer.y; | ||
607 | ev.data = (void *)data; | ||
608 | ev.modifiers = &(e->modifiers); | ||
609 | ev.locks = &(e->locks); | ||
610 | ev.timestamp = timestamp; | ||
611 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
612 | |||
613 | if (copy) eina_list_free(copy); | ||
614 | while (outs) | ||
615 | { | ||
616 | Evas_Object *obj; | ||
617 | |||
618 | obj = outs->data; | ||
619 | outs = eina_list_remove(outs, obj); | ||
620 | if ((obj->mouse_grabbed == 0) && (!e->delete_me)) | ||
621 | { | ||
622 | ev.canvas.x = e->pointer.x; | ||
623 | ev.canvas.y = e->pointer.y; | ||
624 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
625 | e->pointer.object.in = eina_list_remove(e->pointer.object.in, obj); | ||
626 | if (obj->mouse_in) | ||
627 | { | ||
628 | obj->mouse_in = 0; | ||
629 | if (!obj->delete_me) | ||
630 | { | ||
631 | if (e->events_frozen <= 0) | ||
632 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev); | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | } | ||
637 | _evas_post_event_callback_call(e); | ||
638 | } | ||
639 | } | ||
640 | else | ||
641 | { | ||
642 | Eina_List *ins; | ||
643 | Eina_List *l, *copy; | ||
644 | Evas_Event_Mouse_Move ev; | ||
645 | Evas_Event_Mouse_Out ev2; | ||
646 | Evas_Event_Mouse_In ev3; | ||
647 | Evas_Object *obj; | ||
648 | |||
649 | _evas_object_event_new(); | ||
650 | |||
651 | ev.buttons = e->pointer.button; | ||
652 | ev.cur.output.x = e->pointer.x; | ||
653 | ev.cur.output.y = e->pointer.y; | ||
654 | ev.cur.canvas.x = e->pointer.x; | ||
655 | ev.cur.canvas.y = e->pointer.y; | ||
656 | ev.prev.output.x = px; | ||
657 | ev.prev.output.y = py; | ||
658 | ev.prev.canvas.x = px; | ||
659 | ev.prev.canvas.y = py; | ||
660 | ev.data = (void *)data; | ||
661 | ev.modifiers = &(e->modifiers); | ||
662 | ev.locks = &(e->locks); | ||
663 | ev.timestamp = timestamp; | ||
664 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
665 | |||
666 | ev2.buttons = e->pointer.button; | ||
667 | ev2.output.x = e->pointer.x; | ||
668 | ev2.output.y = e->pointer.y; | ||
669 | ev2.canvas.x = e->pointer.x; | ||
670 | ev2.canvas.y = e->pointer.y; | ||
671 | ev2.data = (void *)data; | ||
672 | ev2.modifiers = &(e->modifiers); | ||
673 | ev2.locks = &(e->locks); | ||
674 | ev2.timestamp = timestamp; | ||
675 | ev2.event_flags = EVAS_EVENT_FLAG_NONE; | ||
676 | |||
677 | ev3.buttons = e->pointer.button; | ||
678 | ev3.output.x = e->pointer.x; | ||
679 | ev3.output.y = e->pointer.y; | ||
680 | ev3.canvas.x = e->pointer.x; | ||
681 | ev3.canvas.y = e->pointer.y; | ||
682 | ev3.data = (void *)data; | ||
683 | ev3.modifiers = &(e->modifiers); | ||
684 | ev3.locks = &(e->locks); | ||
685 | ev3.timestamp = timestamp; | ||
686 | ev3.event_flags = EVAS_EVENT_FLAG_NONE; | ||
687 | |||
688 | /* get all new in objects */ | ||
689 | ins = evas_event_objects_event_list(e, NULL, x, y); | ||
690 | /* go thru old list of in objects */ | ||
691 | copy = evas_event_list_copy(e->pointer.object.in); | ||
692 | EINA_LIST_FOREACH(copy, l, obj) | ||
693 | { | ||
694 | /* if its under the pointer and its visible and its in the new */ | ||
695 | /* in list */ | ||
696 | // FIXME: i don't think we need this | ||
697 | // evas_object_clip_recalc(obj); | ||
698 | if ((e->events_frozen <= 0) && | ||
699 | evas_object_is_in_output_rect(obj, x, y, 1, 1) && | ||
700 | (evas_object_clippers_is_visible(obj) || | ||
701 | obj->mouse_grabbed) && | ||
702 | eina_list_data_find(ins, obj) && | ||
703 | (!evas_event_passes_through(obj)) && | ||
704 | (!evas_event_freezes_through(obj)) && | ||
705 | (!obj->clip.clipees) && | ||
706 | ((!obj->precise_is_inside) || evas_object_is_inside(obj, x, y)) | ||
707 | ) | ||
708 | { | ||
709 | if ((px != x) || (py != y)) | ||
710 | { | ||
711 | ev.cur.canvas.x = e->pointer.x; | ||
712 | ev.cur.canvas.y = e->pointer.y; | ||
713 | _evas_event_havemap_adjust(obj, &ev.cur.canvas.x, &ev.cur.canvas.y, obj->mouse_grabbed); | ||
714 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_MOVE, &ev); | ||
715 | } | ||
716 | } | ||
717 | /* otherwise it has left the object */ | ||
718 | else | ||
719 | { | ||
720 | if (obj->mouse_in) | ||
721 | { | ||
722 | obj->mouse_in = 0; | ||
723 | ev2.canvas.x = e->pointer.x; | ||
724 | ev2.canvas.y = e->pointer.y; | ||
725 | _evas_event_havemap_adjust(obj, &ev2.canvas.x, &ev2.canvas.y, obj->mouse_grabbed); | ||
726 | if (e->events_frozen <= 0) | ||
727 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev2); | ||
728 | } | ||
729 | } | ||
730 | if (e->delete_me) break; | ||
731 | } | ||
732 | _evas_post_event_callback_call(e); | ||
733 | |||
734 | _evas_object_event_new(); | ||
735 | |||
736 | if (copy) copy = eina_list_free(copy); | ||
737 | /* go thru our current list of ins */ | ||
738 | EINA_LIST_FOREACH(ins, l, obj) | ||
739 | { | ||
740 | ev3.canvas.x = e->pointer.x; | ||
741 | ev3.canvas.y = e->pointer.y; | ||
742 | _evas_event_havemap_adjust(obj, &ev3.canvas.x, &ev3.canvas.y, obj->mouse_grabbed); | ||
743 | /* if its not in the old list of ins send an enter event */ | ||
744 | if (!eina_list_data_find(e->pointer.object.in, obj)) | ||
745 | { | ||
746 | if (!obj->mouse_in) | ||
747 | { | ||
748 | obj->mouse_in = 1; | ||
749 | if (e->events_frozen <= 0) | ||
750 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_IN, &ev3); | ||
751 | } | ||
752 | } | ||
753 | if (e->delete_me) break; | ||
754 | } | ||
755 | if (e->pointer.mouse_grabbed == 0) | ||
756 | { | ||
757 | /* free our old list of ins */ | ||
758 | eina_list_free(e->pointer.object.in); | ||
759 | /* and set up the new one */ | ||
760 | e->pointer.object.in = ins; | ||
761 | } | ||
762 | else | ||
763 | { | ||
764 | /* free our cur ins */ | ||
765 | eina_list_free(ins); | ||
766 | } | ||
767 | _evas_post_event_callback_call(e); | ||
768 | } | ||
769 | _evas_unwalk(e); | ||
770 | } | ||
771 | |||
772 | EAPI void | ||
773 | evas_event_feed_mouse_in(Evas *e, unsigned int timestamp, const void *data) | ||
774 | { | ||
775 | Eina_List *ins; | ||
776 | Eina_List *l; | ||
777 | Evas_Event_Mouse_In ev; | ||
778 | Evas_Object *obj; | ||
779 | |||
780 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
781 | return; | ||
782 | MAGIC_CHECK_END(); | ||
783 | e->pointer.inside = 1; | ||
784 | |||
785 | if (e->events_frozen > 0) return; | ||
786 | e->last_timestamp = timestamp; | ||
787 | |||
788 | if (e->pointer.mouse_grabbed != 0) return; | ||
789 | |||
790 | _evas_object_event_new(); | ||
791 | |||
792 | ev.buttons = e->pointer.button; | ||
793 | ev.output.x = e->pointer.x; | ||
794 | ev.output.y = e->pointer.y; | ||
795 | ev.canvas.x = e->pointer.x; | ||
796 | ev.canvas.y = e->pointer.y; | ||
797 | ev.data = (void *)data; | ||
798 | ev.modifiers = &(e->modifiers); | ||
799 | ev.locks = &(e->locks); | ||
800 | ev.timestamp = timestamp; | ||
801 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
802 | |||
803 | _evas_walk(e); | ||
804 | /* get new list of ins */ | ||
805 | ins = evas_event_objects_event_list(e, NULL, e->pointer.x, e->pointer.y); | ||
806 | EINA_LIST_FOREACH(ins, l, obj) | ||
807 | { | ||
808 | ev.canvas.x = e->pointer.x; | ||
809 | ev.canvas.y = e->pointer.y; | ||
810 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
811 | if (!eina_list_data_find(e->pointer.object.in, obj)) | ||
812 | { | ||
813 | if (!obj->mouse_in) | ||
814 | { | ||
815 | obj->mouse_in = 1; | ||
816 | if (e->events_frozen <= 0) | ||
817 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_IN, &ev); | ||
818 | } | ||
819 | } | ||
820 | if (e->delete_me) break; | ||
821 | } | ||
822 | /* free our old list of ins */ | ||
823 | e->pointer.object.in = eina_list_free(e->pointer.object.in); | ||
824 | /* and set up the new one */ | ||
825 | e->pointer.object.in = ins; | ||
826 | _evas_post_event_callback_call(e); | ||
827 | evas_event_feed_mouse_move(e, e->pointer.x, e->pointer.y, timestamp, data); | ||
828 | _evas_unwalk(e); | ||
829 | } | ||
830 | |||
831 | EAPI void | ||
832 | evas_event_feed_mouse_out(Evas *e, unsigned int timestamp, const void *data) | ||
833 | { | ||
834 | Evas_Event_Mouse_Out ev; | ||
835 | |||
836 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
837 | return; | ||
838 | MAGIC_CHECK_END(); | ||
839 | e->pointer.inside = 0; | ||
840 | |||
841 | if (e->events_frozen > 0) return; | ||
842 | e->last_timestamp = timestamp; | ||
843 | |||
844 | _evas_object_event_new(); | ||
845 | |||
846 | ev.buttons = e->pointer.button; | ||
847 | ev.output.x = e->pointer.x; | ||
848 | ev.output.y = e->pointer.y; | ||
849 | ev.canvas.x = e->pointer.x; | ||
850 | ev.canvas.y = e->pointer.y; | ||
851 | ev.data = (void *)data; | ||
852 | ev.modifiers = &(e->modifiers); | ||
853 | ev.locks = &(e->locks); | ||
854 | ev.timestamp = timestamp; | ||
855 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
856 | |||
857 | _evas_walk(e); | ||
858 | /* if our mouse button is grabbed to any objects */ | ||
859 | if (e->pointer.mouse_grabbed == 0) | ||
860 | { | ||
861 | /* go thru old list of in objects */ | ||
862 | Eina_List *l, *copy; | ||
863 | Evas_Object *obj; | ||
864 | |||
865 | copy = evas_event_list_copy(e->pointer.object.in); | ||
866 | EINA_LIST_FOREACH(copy, l, obj) | ||
867 | { | ||
868 | ev.canvas.x = e->pointer.x; | ||
869 | ev.canvas.y = e->pointer.y; | ||
870 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
871 | if (obj->mouse_in) | ||
872 | { | ||
873 | obj->mouse_in = 0; | ||
874 | if (!obj->delete_me) | ||
875 | { | ||
876 | if (e->events_frozen <= 0) | ||
877 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev); | ||
878 | } | ||
879 | } | ||
880 | if (e->delete_me) break; | ||
881 | } | ||
882 | if (copy) copy = eina_list_free(copy); | ||
883 | /* free our old list of ins */ | ||
884 | e->pointer.object.in = eina_list_free(e->pointer.object.in); | ||
885 | _evas_post_event_callback_call(e); | ||
886 | } | ||
887 | _evas_unwalk(e); | ||
888 | } | ||
889 | |||
890 | EAPI void | ||
891 | evas_event_feed_multi_down(Evas *e, | ||
892 | int d, int x, int y, | ||
893 | double rad, double radx, double rady, | ||
894 | double pres, double ang, | ||
895 | double fx, double fy, | ||
896 | Evas_Button_Flags flags, unsigned int timestamp, | ||
897 | const void *data) | ||
898 | { | ||
899 | Eina_List *l, *copy; | ||
900 | Evas_Event_Multi_Down ev; | ||
901 | Evas_Object *obj; | ||
902 | |||
903 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
904 | return; | ||
905 | MAGIC_CHECK_END(); | ||
906 | |||
907 | if (e->events_frozen > 0) return; | ||
908 | e->last_timestamp = timestamp; | ||
909 | |||
910 | _evas_object_event_new(); | ||
911 | |||
912 | ev.device = d; | ||
913 | ev.output.x = x; | ||
914 | ev.output.y = y; | ||
915 | ev.canvas.x = x; | ||
916 | ev.canvas.y = y; | ||
917 | ev.radius = rad; | ||
918 | ev.radius_x = radx; | ||
919 | ev.radius_y = rady; | ||
920 | ev.pressure = pres; | ||
921 | ev.angle = ang; | ||
922 | ev.canvas.xsub = fx; | ||
923 | ev.canvas.ysub = fy; | ||
924 | ev.data = (void *)data; | ||
925 | ev.modifiers = &(e->modifiers); | ||
926 | ev.locks = &(e->locks); | ||
927 | ev.flags = flags; | ||
928 | ev.timestamp = timestamp; | ||
929 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
930 | |||
931 | _evas_walk(e); | ||
932 | /* append new touch point to the touch point list */ | ||
933 | _evas_touch_point_append(e, d, x, y); | ||
934 | copy = evas_event_list_copy(e->pointer.object.in); | ||
935 | EINA_LIST_FOREACH(copy, l, obj) | ||
936 | { | ||
937 | if (obj->pointer_mode != EVAS_OBJECT_POINTER_MODE_NOGRAB) | ||
938 | { | ||
939 | obj->mouse_grabbed++; | ||
940 | e->pointer.mouse_grabbed++; | ||
941 | } | ||
942 | } | ||
943 | EINA_LIST_FOREACH(copy, l, obj) | ||
944 | { | ||
945 | ev.canvas.x = x; | ||
946 | ev.canvas.y = y; | ||
947 | ev.canvas.xsub = fx; | ||
948 | ev.canvas.ysub = fy; | ||
949 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
950 | if (x != ev.canvas.x) | ||
951 | ev.canvas.xsub = ev.canvas.x; // fixme - lost precision | ||
952 | if (y != ev.canvas.y) | ||
953 | ev.canvas.ysub = ev.canvas.y; // fixme - lost precision | ||
954 | if (e->events_frozen <= 0) | ||
955 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MULTI_DOWN, &ev); | ||
956 | if (e->delete_me) break; | ||
957 | } | ||
958 | if (copy) eina_list_free(copy); | ||
959 | _evas_post_event_callback_call(e); | ||
960 | /* update touch point's state to EVAS_TOUCH_POINT_STILL */ | ||
961 | _evas_touch_point_update(e, d, x, y, EVAS_TOUCH_POINT_STILL); | ||
962 | _evas_unwalk(e); | ||
963 | } | ||
964 | |||
965 | EAPI void | ||
966 | evas_event_feed_multi_up(Evas *e, | ||
967 | int d, int x, int y, | ||
968 | double rad, double radx, double rady, | ||
969 | double pres, double ang, | ||
970 | double fx, double fy, | ||
971 | Evas_Button_Flags flags, unsigned int timestamp, | ||
972 | const void *data) | ||
973 | { | ||
974 | Eina_List *l, *copy; | ||
975 | Evas_Event_Multi_Up ev; | ||
976 | Evas_Object *obj; | ||
977 | |||
978 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
979 | return; | ||
980 | MAGIC_CHECK_END(); | ||
981 | |||
982 | if (e->events_frozen > 0) return; | ||
983 | e->last_timestamp = timestamp; | ||
984 | |||
985 | _evas_object_event_new(); | ||
986 | |||
987 | ev.device = d; | ||
988 | ev.output.x = x; | ||
989 | ev.output.y = y; | ||
990 | ev.canvas.x = x; | ||
991 | ev.canvas.y = y; | ||
992 | ev.radius = rad; | ||
993 | ev.radius_x = radx; | ||
994 | ev.radius_y = rady; | ||
995 | ev.pressure = pres; | ||
996 | ev.angle = ang; | ||
997 | ev.canvas.xsub = fx; | ||
998 | ev.canvas.ysub = fy; | ||
999 | ev.data = (void *)data; | ||
1000 | ev.modifiers = &(e->modifiers); | ||
1001 | ev.locks = &(e->locks); | ||
1002 | ev.flags = flags; | ||
1003 | ev.timestamp = timestamp; | ||
1004 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
1005 | |||
1006 | _evas_walk(e); | ||
1007 | /* update released touch point */ | ||
1008 | _evas_touch_point_update(e, d, x, y, EVAS_TOUCH_POINT_UP); | ||
1009 | copy = evas_event_list_copy(e->pointer.object.in); | ||
1010 | EINA_LIST_FOREACH(copy, l, obj) | ||
1011 | { | ||
1012 | ev.canvas.x = x; | ||
1013 | ev.canvas.y = y; | ||
1014 | ev.canvas.xsub = fx; | ||
1015 | ev.canvas.ysub = fy; | ||
1016 | _evas_event_havemap_adjust(obj, &ev.canvas.x, &ev.canvas.y, obj->mouse_grabbed); | ||
1017 | if (x != ev.canvas.x) | ||
1018 | ev.canvas.xsub = ev.canvas.x; // fixme - lost precision | ||
1019 | if (y != ev.canvas.y) | ||
1020 | ev.canvas.ysub = ev.canvas.y; // fixme - lost precision | ||
1021 | if ((obj->pointer_mode != EVAS_OBJECT_POINTER_MODE_NOGRAB) && | ||
1022 | (obj->mouse_grabbed > 0)) | ||
1023 | { | ||
1024 | obj->mouse_grabbed--; | ||
1025 | e->pointer.mouse_grabbed--; | ||
1026 | } | ||
1027 | if (e->events_frozen <= 0) | ||
1028 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MULTI_UP, &ev); | ||
1029 | if (e->delete_me) break; | ||
1030 | } | ||
1031 | if (copy) copy = eina_list_free(copy); | ||
1032 | if ((e->pointer.mouse_grabbed == 0) && !_post_up_handle(e, timestamp, data)) | ||
1033 | _evas_post_event_callback_call(e); | ||
1034 | /* remove released touch point from the touch point list */ | ||
1035 | _evas_touch_point_remove(e, d); | ||
1036 | _evas_unwalk(e); | ||
1037 | } | ||
1038 | |||
1039 | EAPI void | ||
1040 | evas_event_feed_multi_move(Evas *e, | ||
1041 | int d, int x, int y, | ||
1042 | double rad, double radx, double rady, | ||
1043 | double pres, double ang, | ||
1044 | double fx, double fy, | ||
1045 | unsigned int timestamp, const void *data) | ||
1046 | { | ||
1047 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1048 | return; | ||
1049 | MAGIC_CHECK_END(); | ||
1050 | |||
1051 | if (e->events_frozen > 0) return; | ||
1052 | e->last_timestamp = timestamp; | ||
1053 | |||
1054 | if (!e->pointer.inside) return; | ||
1055 | |||
1056 | _evas_walk(e); | ||
1057 | /* update moved touch point */ | ||
1058 | _evas_touch_point_update(e, d, x, y, EVAS_TOUCH_POINT_MOVE); | ||
1059 | /* if our mouse button is grabbed to any objects */ | ||
1060 | if (e->pointer.mouse_grabbed > 0) | ||
1061 | { | ||
1062 | /* go thru old list of in objects */ | ||
1063 | Eina_List *l, *copy; | ||
1064 | Evas_Event_Multi_Move ev; | ||
1065 | Evas_Object *obj; | ||
1066 | |||
1067 | _evas_object_event_new(); | ||
1068 | |||
1069 | ev.device = d; | ||
1070 | ev.cur.output.x = x; | ||
1071 | ev.cur.output.y = y; | ||
1072 | ev.cur.canvas.x = x; | ||
1073 | ev.cur.canvas.y = y; | ||
1074 | ev.radius = rad; | ||
1075 | ev.radius_x = radx; | ||
1076 | ev.radius_y = rady; | ||
1077 | ev.pressure = pres; | ||
1078 | ev.angle = ang; | ||
1079 | ev.cur.canvas.xsub = fx; | ||
1080 | ev.cur.canvas.ysub = fy; | ||
1081 | ev.data = (void *)data; | ||
1082 | ev.modifiers = &(e->modifiers); | ||
1083 | ev.locks = &(e->locks); | ||
1084 | ev.timestamp = timestamp; | ||
1085 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
1086 | |||
1087 | copy = evas_event_list_copy(e->pointer.object.in); | ||
1088 | EINA_LIST_FOREACH(copy, l, obj) | ||
1089 | { | ||
1090 | if ((e->events_frozen <= 0) && | ||
1091 | (evas_object_clippers_is_visible(obj) || obj->mouse_grabbed) && | ||
1092 | (!evas_event_passes_through(obj)) && | ||
1093 | (!evas_event_freezes_through(obj)) && | ||
1094 | (!obj->clip.clipees)) | ||
1095 | { | ||
1096 | ev.cur.canvas.x = x; | ||
1097 | ev.cur.canvas.y = y; | ||
1098 | ev.cur.canvas.xsub = fx; | ||
1099 | ev.cur.canvas.ysub = fy; | ||
1100 | _evas_event_havemap_adjust(obj, &ev.cur.canvas.x, &ev.cur.canvas.y, obj->mouse_grabbed); | ||
1101 | if (x != ev.cur.canvas.x) | ||
1102 | ev.cur.canvas.xsub = ev.cur.canvas.x; // fixme - lost precision | ||
1103 | if (y != ev.cur.canvas.y) | ||
1104 | ev.cur.canvas.ysub = ev.cur.canvas.y; // fixme - lost precision | ||
1105 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MULTI_MOVE, &ev); | ||
1106 | } | ||
1107 | if (e->delete_me) break; | ||
1108 | } | ||
1109 | _evas_post_event_callback_call(e); | ||
1110 | } | ||
1111 | else | ||
1112 | { | ||
1113 | Eina_List *ins; | ||
1114 | Eina_List *l, *copy; | ||
1115 | Evas_Event_Multi_Move ev; | ||
1116 | Evas_Object *obj; | ||
1117 | |||
1118 | _evas_object_event_new(); | ||
1119 | |||
1120 | ev.device = d; | ||
1121 | ev.cur.output.x = x; | ||
1122 | ev.cur.output.y = y; | ||
1123 | ev.cur.canvas.x = x; | ||
1124 | ev.cur.canvas.y = y; | ||
1125 | ev.radius = rad; | ||
1126 | ev.radius_x = radx; | ||
1127 | ev.radius_y = rady; | ||
1128 | ev.pressure = pres; | ||
1129 | ev.angle = ang; | ||
1130 | ev.cur.canvas.xsub = fx; | ||
1131 | ev.cur.canvas.ysub = fy; | ||
1132 | ev.data = (void *)data; | ||
1133 | ev.modifiers = &(e->modifiers); | ||
1134 | ev.locks = &(e->locks); | ||
1135 | ev.timestamp = timestamp; | ||
1136 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
1137 | |||
1138 | /* get all new in objects */ | ||
1139 | ins = evas_event_objects_event_list(e, NULL, x, y); | ||
1140 | /* go thru old list of in objects */ | ||
1141 | copy = evas_event_list_copy(e->pointer.object.in); | ||
1142 | EINA_LIST_FOREACH(copy, l, obj) | ||
1143 | { | ||
1144 | /* if its under the pointer and its visible and its in the new */ | ||
1145 | /* in list */ | ||
1146 | // FIXME: i don't think we need this | ||
1147 | // evas_object_clip_recalc(obj); | ||
1148 | if ((e->events_frozen <= 0) && | ||
1149 | evas_object_is_in_output_rect(obj, x, y, 1, 1) && | ||
1150 | (evas_object_clippers_is_visible(obj) || | ||
1151 | obj->mouse_grabbed) && | ||
1152 | eina_list_data_find(ins, obj) && | ||
1153 | (!evas_event_passes_through(obj)) && | ||
1154 | (!evas_event_freezes_through(obj)) && | ||
1155 | (!obj->clip.clipees) && | ||
1156 | ((!obj->precise_is_inside) || evas_object_is_inside(obj, x, y)) | ||
1157 | ) | ||
1158 | { | ||
1159 | ev.cur.canvas.x = x; | ||
1160 | ev.cur.canvas.y = y; | ||
1161 | ev.cur.canvas.xsub = fx; | ||
1162 | ev.cur.canvas.ysub = fy; | ||
1163 | _evas_event_havemap_adjust(obj, &ev.cur.canvas.x, &ev.cur.canvas.y, obj->mouse_grabbed); | ||
1164 | if (x != ev.cur.canvas.x) | ||
1165 | ev.cur.canvas.xsub = ev.cur.canvas.x; // fixme - lost precision | ||
1166 | if (y != ev.cur.canvas.y) | ||
1167 | ev.cur.canvas.ysub = ev.cur.canvas.y; // fixme - lost precision | ||
1168 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MULTI_MOVE, &ev); | ||
1169 | } | ||
1170 | if (e->delete_me) break; | ||
1171 | } | ||
1172 | if (copy) copy = eina_list_free(copy); | ||
1173 | if (e->pointer.mouse_grabbed == 0) | ||
1174 | { | ||
1175 | /* free our old list of ins */ | ||
1176 | eina_list_free(e->pointer.object.in); | ||
1177 | /* and set up the new one */ | ||
1178 | e->pointer.object.in = ins; | ||
1179 | } | ||
1180 | else | ||
1181 | { | ||
1182 | /* free our cur ins */ | ||
1183 | eina_list_free(ins); | ||
1184 | } | ||
1185 | _evas_post_event_callback_call(e); | ||
1186 | } | ||
1187 | _evas_unwalk(e); | ||
1188 | } | ||
1189 | |||
1190 | EAPI void | ||
1191 | evas_event_feed_key_down(Evas *e, const char *keyname, const char *key, const char *string, const char *compose, unsigned int timestamp, const void *data) | ||
1192 | { | ||
1193 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1194 | return; | ||
1195 | MAGIC_CHECK_END(); | ||
1196 | |||
1197 | if (!keyname) return; | ||
1198 | if (e->events_frozen > 0) return; | ||
1199 | e->last_timestamp = timestamp; | ||
1200 | _evas_walk(e); | ||
1201 | |||
1202 | Evas_Event_Key_Down ev; | ||
1203 | Eina_Bool exclusive; | ||
1204 | |||
1205 | _evas_object_event_new(); | ||
1206 | |||
1207 | exclusive = EINA_FALSE; | ||
1208 | ev.keyname = (char *)keyname; | ||
1209 | ev.data = (void *)data; | ||
1210 | ev.modifiers = &(e->modifiers); | ||
1211 | ev.locks = &(e->locks); | ||
1212 | ev.key = key; | ||
1213 | ev.string = string; | ||
1214 | ev.compose = compose; | ||
1215 | ev.timestamp = timestamp; | ||
1216 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
1217 | |||
1218 | if (e->grabs) | ||
1219 | { | ||
1220 | Eina_List *l; | ||
1221 | Evas_Key_Grab *g; | ||
1222 | |||
1223 | e->walking_grabs++; | ||
1224 | EINA_LIST_FOREACH(e->grabs, l, g) | ||
1225 | { | ||
1226 | if (g->just_added) | ||
1227 | { | ||
1228 | g->just_added = EINA_FALSE; | ||
1229 | continue; | ||
1230 | } | ||
1231 | if (g->delete_me) continue; | ||
1232 | if (((e->modifiers.mask & g->modifiers) || | ||
1233 | (g->modifiers == e->modifiers.mask)) && | ||
1234 | (!strcmp(keyname, g->keyname))) | ||
1235 | { | ||
1236 | if (!(e->modifiers.mask & g->not_modifiers)) | ||
1237 | { | ||
1238 | if (e->events_frozen <= 0 && | ||
1239 | !evas_event_freezes_through(g->object)) | ||
1240 | evas_object_event_callback_call(g->object, | ||
1241 | EVAS_CALLBACK_KEY_DOWN, | ||
1242 | &ev); | ||
1243 | if (g->exclusive) exclusive = EINA_TRUE; | ||
1244 | } | ||
1245 | } | ||
1246 | if (e->delete_me) break; | ||
1247 | } | ||
1248 | e->walking_grabs--; | ||
1249 | if (e->walking_grabs <= 0) | ||
1250 | { | ||
1251 | while (e->delete_grabs > 0) | ||
1252 | { | ||
1253 | e->delete_grabs--; | ||
1254 | for (l = e->grabs; l;) | ||
1255 | { | ||
1256 | g = eina_list_data_get(l); | ||
1257 | l = eina_list_next(l); | ||
1258 | if (g->delete_me) | ||
1259 | evas_key_grab_free(g->object, g->keyname, g->modifiers, | ||
1260 | g->not_modifiers); | ||
1261 | } | ||
1262 | } | ||
1263 | } | ||
1264 | } | ||
1265 | if ((e->focused) && (!exclusive)) | ||
1266 | { | ||
1267 | if (e->events_frozen <= 0 && !evas_event_freezes_through(e->focused)) | ||
1268 | evas_object_event_callback_call(e->focused, EVAS_CALLBACK_KEY_DOWN, | ||
1269 | &ev); | ||
1270 | } | ||
1271 | _evas_post_event_callback_call(e); | ||
1272 | _evas_unwalk(e); | ||
1273 | } | ||
1274 | |||
1275 | EAPI void | ||
1276 | evas_event_feed_key_up(Evas *e, const char *keyname, const char *key, const char *string, const char *compose, unsigned int timestamp, const void *data) | ||
1277 | { | ||
1278 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1279 | return; | ||
1280 | MAGIC_CHECK_END(); | ||
1281 | if (!keyname) return; | ||
1282 | if (e->events_frozen > 0) return; | ||
1283 | e->last_timestamp = timestamp; | ||
1284 | _evas_walk(e); | ||
1285 | |||
1286 | Evas_Event_Key_Up ev; | ||
1287 | Eina_Bool exclusive; | ||
1288 | |||
1289 | _evas_object_event_new(); | ||
1290 | |||
1291 | exclusive = EINA_FALSE; | ||
1292 | ev.keyname = (char *)keyname; | ||
1293 | ev.data = (void *)data; | ||
1294 | ev.modifiers = &(e->modifiers); | ||
1295 | ev.locks = &(e->locks); | ||
1296 | ev.key = key; | ||
1297 | ev.string = string; | ||
1298 | ev.compose = compose; | ||
1299 | ev.timestamp = timestamp; | ||
1300 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
1301 | |||
1302 | if (e->grabs) | ||
1303 | { | ||
1304 | Eina_List *l; | ||
1305 | Evas_Key_Grab *g; | ||
1306 | |||
1307 | e->walking_grabs++; | ||
1308 | EINA_LIST_FOREACH(e->grabs, l, g) | ||
1309 | { | ||
1310 | if (g->just_added) | ||
1311 | { | ||
1312 | g->just_added = EINA_FALSE; | ||
1313 | continue; | ||
1314 | } | ||
1315 | if (g->delete_me) continue; | ||
1316 | if (((e->modifiers.mask & g->modifiers) || | ||
1317 | (g->modifiers == e->modifiers.mask)) && | ||
1318 | (!((e->modifiers.mask & g->not_modifiers) || | ||
1319 | (g->not_modifiers == ~e->modifiers.mask))) && | ||
1320 | (!strcmp(keyname, g->keyname))) | ||
1321 | { | ||
1322 | if (e->events_frozen <= 0 && | ||
1323 | !evas_event_freezes_through(g->object)) | ||
1324 | evas_object_event_callback_call(g->object, | ||
1325 | EVAS_CALLBACK_KEY_UP, &ev); | ||
1326 | if (g->exclusive) exclusive = EINA_TRUE; | ||
1327 | } | ||
1328 | if (e->delete_me) break; | ||
1329 | } | ||
1330 | e->walking_grabs--; | ||
1331 | if (e->walking_grabs <= 0) | ||
1332 | { | ||
1333 | while (e->delete_grabs > 0) | ||
1334 | { | ||
1335 | Eina_List *ll, *l_next; | ||
1336 | Evas_Key_Grab *gr; | ||
1337 | |||
1338 | e->delete_grabs--; | ||
1339 | EINA_LIST_FOREACH_SAFE(e->grabs, ll, l_next, gr) | ||
1340 | { | ||
1341 | if (gr->delete_me) | ||
1342 | evas_key_grab_free(gr->object, gr->keyname, | ||
1343 | gr->modifiers, gr->not_modifiers); | ||
1344 | } | ||
1345 | } | ||
1346 | } | ||
1347 | } | ||
1348 | if ((e->focused) && (!exclusive)) | ||
1349 | { | ||
1350 | if (e->events_frozen <= 0 && !evas_event_freezes_through(e->focused)) | ||
1351 | evas_object_event_callback_call(e->focused, EVAS_CALLBACK_KEY_UP, | ||
1352 | &ev); | ||
1353 | } | ||
1354 | _evas_post_event_callback_call(e); | ||
1355 | _evas_unwalk(e); | ||
1356 | } | ||
1357 | |||
1358 | EAPI void | ||
1359 | evas_event_feed_hold(Evas *e, int hold, unsigned int timestamp, const void *data) | ||
1360 | { | ||
1361 | Eina_List *l, *copy; | ||
1362 | Evas_Event_Hold ev; | ||
1363 | Evas_Object *obj; | ||
1364 | |||
1365 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1366 | return; | ||
1367 | MAGIC_CHECK_END(); | ||
1368 | |||
1369 | if (e->events_frozen > 0) return; | ||
1370 | e->last_timestamp = timestamp; | ||
1371 | |||
1372 | _evas_object_event_new(); | ||
1373 | |||
1374 | ev.hold = hold; | ||
1375 | ev.data = (void *)data; | ||
1376 | ev.timestamp = timestamp; | ||
1377 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
1378 | |||
1379 | _evas_walk(e); | ||
1380 | copy = evas_event_list_copy(e->pointer.object.in); | ||
1381 | EINA_LIST_FOREACH(copy, l, obj) | ||
1382 | { | ||
1383 | if ((e->events_frozen <= 0) && !evas_event_freezes_through(obj)) | ||
1384 | evas_object_event_callback_call(obj, EVAS_CALLBACK_HOLD, &ev); | ||
1385 | if (e->delete_me) break; | ||
1386 | } | ||
1387 | if (copy) copy = eina_list_free(copy); | ||
1388 | _evas_post_event_callback_call(e); | ||
1389 | _evas_unwalk(e); | ||
1390 | _evas_object_event_new(); | ||
1391 | } | ||
1392 | |||
1393 | EAPI void | ||
1394 | evas_object_freeze_events_set(Evas_Object *obj, Eina_Bool freeze) | ||
1395 | { | ||
1396 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1397 | return; | ||
1398 | MAGIC_CHECK_END(); | ||
1399 | |||
1400 | freeze = !!freeze; | ||
1401 | if (obj->freeze_events == freeze) return; | ||
1402 | obj->freeze_events = freeze; | ||
1403 | evas_object_smart_member_cache_invalidate(obj, EINA_FALSE, EINA_TRUE); | ||
1404 | if (evas_object_is_in_output_rect(obj, | ||
1405 | obj->layer->evas->pointer.x, | ||
1406 | obj->layer->evas->pointer.y, 1, 1) && | ||
1407 | ((!obj->precise_is_inside) || | ||
1408 | (evas_object_is_inside(obj, | ||
1409 | obj->layer->evas->pointer.x, | ||
1410 | obj->layer->evas->pointer.y)))) | ||
1411 | evas_event_feed_mouse_move(obj->layer->evas, | ||
1412 | obj->layer->evas->pointer.x, | ||
1413 | obj->layer->evas->pointer.y, | ||
1414 | obj->layer->evas->last_timestamp, | ||
1415 | NULL); | ||
1416 | } | ||
1417 | |||
1418 | EAPI Eina_Bool | ||
1419 | evas_object_freeze_events_get(const Evas_Object *obj) | ||
1420 | { | ||
1421 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1422 | return EINA_FALSE; | ||
1423 | MAGIC_CHECK_END(); | ||
1424 | return obj->freeze_events; | ||
1425 | } | ||
1426 | |||
1427 | EAPI void | ||
1428 | evas_object_pass_events_set(Evas_Object *obj, Eina_Bool pass) | ||
1429 | { | ||
1430 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1431 | return; | ||
1432 | MAGIC_CHECK_END(); | ||
1433 | pass = !!pass; | ||
1434 | if (obj->pass_events == pass) return; | ||
1435 | obj->pass_events = pass; | ||
1436 | evas_object_smart_member_cache_invalidate(obj, EINA_TRUE, EINA_FALSE); | ||
1437 | if (evas_object_is_in_output_rect(obj, | ||
1438 | obj->layer->evas->pointer.x, | ||
1439 | obj->layer->evas->pointer.y, 1, 1) && | ||
1440 | ((!obj->precise_is_inside) || | ||
1441 | (evas_object_is_inside(obj, | ||
1442 | obj->layer->evas->pointer.x, | ||
1443 | obj->layer->evas->pointer.y)))) | ||
1444 | evas_event_feed_mouse_move(obj->layer->evas, | ||
1445 | obj->layer->evas->pointer.x, | ||
1446 | obj->layer->evas->pointer.y, | ||
1447 | obj->layer->evas->last_timestamp, | ||
1448 | NULL); | ||
1449 | } | ||
1450 | |||
1451 | EAPI Eina_Bool | ||
1452 | evas_object_pass_events_get(const Evas_Object *obj) | ||
1453 | { | ||
1454 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1455 | return EINA_FALSE; | ||
1456 | MAGIC_CHECK_END(); | ||
1457 | return obj->pass_events; | ||
1458 | } | ||
1459 | |||
1460 | EAPI void | ||
1461 | evas_object_repeat_events_set(Evas_Object *obj, Eina_Bool repeat) | ||
1462 | { | ||
1463 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1464 | return; | ||
1465 | MAGIC_CHECK_END(); | ||
1466 | repeat = !!repeat; | ||
1467 | if (obj->repeat_events == repeat) return; | ||
1468 | obj->repeat_events = repeat; | ||
1469 | if (evas_object_is_in_output_rect(obj, | ||
1470 | obj->layer->evas->pointer.x, | ||
1471 | obj->layer->evas->pointer.y, 1, 1) && | ||
1472 | ((!obj->precise_is_inside) || | ||
1473 | (evas_object_is_inside(obj, | ||
1474 | obj->layer->evas->pointer.x, | ||
1475 | obj->layer->evas->pointer.y)))) | ||
1476 | evas_event_feed_mouse_move(obj->layer->evas, | ||
1477 | obj->layer->evas->pointer.x, | ||
1478 | obj->layer->evas->pointer.y, | ||
1479 | obj->layer->evas->last_timestamp, | ||
1480 | NULL); | ||
1481 | } | ||
1482 | |||
1483 | EAPI Eina_Bool | ||
1484 | evas_object_repeat_events_get(const Evas_Object *obj) | ||
1485 | { | ||
1486 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1487 | return EINA_FALSE; | ||
1488 | MAGIC_CHECK_END(); | ||
1489 | return obj->repeat_events; | ||
1490 | } | ||
1491 | |||
1492 | EAPI void | ||
1493 | evas_object_propagate_events_set(Evas_Object *obj, Eina_Bool prop) | ||
1494 | { | ||
1495 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1496 | return; | ||
1497 | MAGIC_CHECK_END(); | ||
1498 | obj->no_propagate = !prop; | ||
1499 | } | ||
1500 | |||
1501 | EAPI Eina_Bool | ||
1502 | evas_object_propagate_events_get(const Evas_Object *obj) | ||
1503 | { | ||
1504 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1505 | return EINA_FALSE; | ||
1506 | MAGIC_CHECK_END(); | ||
1507 | return !(obj->no_propagate); | ||
1508 | } | ||
1509 | |||
1510 | EAPI void | ||
1511 | evas_object_pointer_mode_set(Evas_Object *obj, Evas_Object_Pointer_Mode setting) | ||
1512 | { | ||
1513 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1514 | return; | ||
1515 | MAGIC_CHECK_END(); | ||
1516 | obj->pointer_mode = setting; | ||
1517 | } | ||
1518 | |||
1519 | EAPI Evas_Object_Pointer_Mode | ||
1520 | evas_object_pointer_mode_get(const Evas_Object *obj) | ||
1521 | { | ||
1522 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1523 | return EVAS_OBJECT_POINTER_MODE_AUTOGRAB; | ||
1524 | MAGIC_CHECK_END(); | ||
1525 | return obj->pointer_mode; | ||
1526 | } | ||
1527 | |||
1528 | EAPI void | ||
1529 | evas_event_refeed_event(Evas *e, void *event_copy, Evas_Callback_Type event_type) | ||
1530 | { | ||
1531 | switch(event_type) | ||
1532 | { | ||
1533 | case EVAS_CALLBACK_MOUSE_IN: | ||
1534 | { | ||
1535 | Evas_Event_Mouse_In *ev = event_copy; | ||
1536 | evas_event_feed_mouse_in(e, ev->timestamp, ev->data); | ||
1537 | break; | ||
1538 | } | ||
1539 | case EVAS_CALLBACK_MOUSE_OUT: | ||
1540 | { | ||
1541 | Evas_Event_Mouse_Out *ev = event_copy; | ||
1542 | evas_event_feed_mouse_out(e, ev->timestamp, ev->data); | ||
1543 | break; | ||
1544 | } | ||
1545 | case EVAS_CALLBACK_MOUSE_DOWN: | ||
1546 | { | ||
1547 | Evas_Event_Mouse_Down *ev = event_copy; | ||
1548 | evas_event_feed_mouse_down(e, ev->button, ev->flags, ev-> timestamp, ev->data); | ||
1549 | break; | ||
1550 | } | ||
1551 | case EVAS_CALLBACK_MOUSE_UP: | ||
1552 | { | ||
1553 | Evas_Event_Mouse_Up *ev = event_copy; | ||
1554 | evas_event_feed_mouse_up(e, ev->button, ev->flags, ev-> timestamp, ev->data); | ||
1555 | break; | ||
1556 | } | ||
1557 | case EVAS_CALLBACK_MOUSE_MOVE: | ||
1558 | { | ||
1559 | Evas_Event_Mouse_Move *ev = event_copy; | ||
1560 | evas_event_feed_mouse_move(e, ev->cur.canvas.x, ev->cur.canvas.y, ev->timestamp, ev->data); | ||
1561 | break; | ||
1562 | } | ||
1563 | case EVAS_CALLBACK_MOUSE_WHEEL: | ||
1564 | { | ||
1565 | Evas_Event_Mouse_Wheel *ev = event_copy; | ||
1566 | evas_event_feed_mouse_wheel(e, ev->direction, ev-> z, ev->timestamp, ev->data); | ||
1567 | break; | ||
1568 | } | ||
1569 | case EVAS_CALLBACK_MULTI_DOWN: | ||
1570 | { | ||
1571 | Evas_Event_Multi_Down *ev = event_copy; | ||
1572 | evas_event_feed_multi_down(e, ev->device, ev->canvas.x, ev->canvas.y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, ev->canvas.xsub, ev->canvas.ysub, ev->flags, ev->timestamp, ev->data); | ||
1573 | break; | ||
1574 | } | ||
1575 | case EVAS_CALLBACK_MULTI_UP: | ||
1576 | { | ||
1577 | Evas_Event_Multi_Up *ev = event_copy; | ||
1578 | evas_event_feed_multi_up(e, ev->device, ev->canvas.x, ev->canvas.y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, ev->canvas.xsub, ev->canvas.ysub, ev->flags, ev->timestamp, ev->data); | ||
1579 | break; | ||
1580 | } | ||
1581 | case EVAS_CALLBACK_MULTI_MOVE: | ||
1582 | { | ||
1583 | Evas_Event_Multi_Move *ev = event_copy; | ||
1584 | evas_event_feed_multi_move(e, ev->device, ev->cur.canvas.x, ev->cur.canvas.y, ev->radius, ev->radius_x, ev->radius_y, ev->pressure, ev->angle, ev->cur.canvas.xsub, ev->cur.canvas.ysub, ev->timestamp, ev->data); | ||
1585 | break; | ||
1586 | } | ||
1587 | case EVAS_CALLBACK_KEY_DOWN: | ||
1588 | { | ||
1589 | Evas_Event_Key_Down *ev = event_copy; | ||
1590 | evas_event_feed_key_down(e, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, ev->data); | ||
1591 | break; | ||
1592 | } | ||
1593 | case EVAS_CALLBACK_KEY_UP: | ||
1594 | { | ||
1595 | Evas_Event_Key_Up *ev = event_copy; | ||
1596 | evas_event_feed_key_up(e, ev->keyname, ev->key, ev->string, ev->compose, ev->timestamp, ev->data); | ||
1597 | break; | ||
1598 | } | ||
1599 | default: /* All non-input events are not handeled */ | ||
1600 | break; | ||
1601 | } | ||
1602 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_filter.c b/libraries/evas/src/lib/canvas/evas_filter.c new file mode 100644 index 0000000..6194ec2 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_filter.c | |||
@@ -0,0 +1,1427 @@ | |||
1 | /* | ||
2 | * Filter implementation for evas | ||
3 | */ | ||
4 | |||
5 | #if 0 // filtering disabled | ||
6 | typedef enum | ||
7 | { | ||
8 | /** Apply any filter effects to this object (Default) */ | ||
9 | EVAS_FILTER_MODE_OBJECT, | ||
10 | /** Filter all objects beneath this object on the canvas */ | ||
11 | EVAS_FILTER_MODE_BELOW, | ||
12 | } Evas_Filter_Mode; | ||
13 | typedef enum | ||
14 | { | ||
15 | /** No filter: Default */ | ||
16 | EVAS_FILTER_NONE, | ||
17 | /** A blur filter. Params are quality (float), and radius (int). */ | ||
18 | EVAS_FILTER_BLUR, | ||
19 | /** Negates the colors of an image. Also called solarize */ | ||
20 | EVAS_FILTER_INVERT, | ||
21 | EVAS_FILTER_SOLARIZE = EVAS_FILTER_INVERT, | ||
22 | /** Makes a sepia version of the image. */ | ||
23 | EVAS_FILTER_SEPIA, | ||
24 | /** Makes a greyscale version of the image. Params are 'red', | ||
25 | * 'green', 'blue' (all floats) which must add to 1. The defaults are | ||
26 | * 0.3, 0.59 and 0.11 which approximates human vision. Setting 'all' | ||
27 | * sets rgb to the same value. */ | ||
28 | EVAS_FILTER_GREYSCALE, | ||
29 | EVAS_FILTER_GRAYSCALE = EVAS_FILTER_GREYSCALE, | ||
30 | /** Brighten (or darken) image. Param 'adjust' float (-1.0 to 1.0) | ||
31 | * amount to adjust. */ | ||
32 | EVAS_FILTER_BRIGHTNESS, | ||
33 | /** Enhance contrast on image. Param 'adjust' float (-1.0 to 1.0) | ||
34 | * amount to adjust. */ | ||
35 | EVAS_FILTER_CONTRAST, | ||
36 | |||
37 | EVAS_FILTER_LAST = EVAS_FILTER_CONTRAST | ||
38 | } Evas_Filter; | ||
39 | |||
40 | /** | ||
41 | * Set the filter mode for an object. | ||
42 | * | ||
43 | * There are two valid filtering modes currently: | ||
44 | * - EVAS_FILTER_MODE_OBJECT: which applies the filter to the object itself | ||
45 | * - EVAS_FILTER_MODE_BELOW: which makes the object invisible and filters | ||
46 | * what is below the object. | ||
47 | * | ||
48 | * The default filter mode is EVAS_FILTER_MODE_OBJECT. | ||
49 | * | ||
50 | * @param o Object to set filter mode on. | ||
51 | * @param mode Mode to set. | ||
52 | * @return EINA_TRUE on success, EINA_FALSE otherwise. | ||
53 | */ | ||
54 | EAPI Eina_Bool evas_object_filter_mode_set (Evas_Object *o, Evas_Filter_Mode mode); | ||
55 | |||
56 | /** | ||
57 | * Get the current filtering mode for an object. | ||
58 | * | ||
59 | * By default all objects are in object filtering mode, even if no filter is | ||
60 | * set. | ||
61 | * | ||
62 | * @param o Object to get filter mode of. | ||
63 | * @return Filter mode (default EVAS_FILTER_MODE_OBJECT) | ||
64 | */ | ||
65 | EAPI Evas_Filter_Mode evas_object_filter_mode_get (Evas_Object *o); | ||
66 | |||
67 | /** | ||
68 | * Set the current filter type. | ||
69 | * | ||
70 | * This sets the filter type, whether a blur, color filter or some other type | ||
71 | * of filter. This is normally the only filter call necessary, although some | ||
72 | * filters require additional parameters. | ||
73 | * | ||
74 | * If the object has a filter already, and existing parameters will be | ||
75 | * cleared. | ||
76 | * | ||
77 | * Setting the blur to EVAS_FILTER_NONE removes any filter. | ||
78 | * | ||
79 | * @param o Object to set the filter on. | ||
80 | * @param filter Filter to set. | ||
81 | * @return EINA_TRUE On success | ||
82 | */ | ||
83 | EAPI Eina_Bool evas_object_filter_set (Evas_Object *o, Evas_Filter filter); | ||
84 | |||
85 | /** | ||
86 | * Get the current filter. | ||
87 | * | ||
88 | * @param o Object to get filter of. | ||
89 | * @return The filter if set, or EVAS_FILTER_NONE. | ||
90 | */ | ||
91 | EAPI Evas_Filter evas_object_filter_get (Evas_Object *o); | ||
92 | |||
93 | /** | ||
94 | * Set an integer parameter of a filter. | ||
95 | * | ||
96 | * This sets an integer parameter of a filter, if such parameter is known to | ||
97 | * the filter. Note that some parameters may actually set multiple fields. | ||
98 | * The individual filters define the specific parameters available. | ||
99 | * | ||
100 | * It should be noted that filter parameters are lost after the filter type | ||
101 | * changes, so set the filter type, then the parameters. | ||
102 | * | ||
103 | * @param o Object to set parameter on. | ||
104 | * @param param Name of parameter to set. | ||
105 | * @param val Value to set. | ||
106 | * @return EINA_TRUE if at least one parameter was set, EINA_FALSE | ||
107 | * otherwise. | ||
108 | */ | ||
109 | EAPI Eina_Bool evas_object_filter_param_int_set (Evas_Object *o, const char *param, int val); | ||
110 | |||
111 | /** | ||
112 | * Get an integer value parameter from a filter. | ||
113 | * | ||
114 | * Gets the first matching parameter for a filter. Note there is no way to | ||
115 | * later fields if they do not have their own accessor name. | ||
116 | * | ||
117 | * Also note that there is no way to tell the difference between a -1 as a | ||
118 | * value, and the error code. Ask your filter writer to use a different | ||
119 | * range. | ||
120 | * | ||
121 | * @param o The object. | ||
122 | * @Param param Name of the parameter to get. | ||
123 | * @return The value, or -1 on error. | ||
124 | */ | ||
125 | EAPI int evas_object_filter_param_int_get (Evas_Object *o, const char *param); | ||
126 | |||
127 | /** | ||
128 | * Set a string parameter on a filter | ||
129 | * | ||
130 | * Currently unimplemented as no filters use this yet | ||
131 | */ | ||
132 | EAPI Eina_Bool evas_object_filter_param_str_set (Evas_Object *o, const char *param, const char *val); | ||
133 | |||
134 | /** | ||
135 | * Get a string parameter from a filter | ||
136 | * | ||
137 | * Currently unimplemented as no filters use this yet | ||
138 | */ | ||
139 | EAPI const char *evas_object_filter_param_str_get (Evas_Object *o, const char *param); | ||
140 | |||
141 | /** | ||
142 | * Set an object parameter on a filter | ||
143 | * | ||
144 | * Currently unimplemented as no filters use this yet | ||
145 | */ | ||
146 | EAPI Eina_Bool evas_object_filter_param_obj_set (Evas_Object *o, const char *param, Evas_Object *val); | ||
147 | |||
148 | /** | ||
149 | * get an object parameter from a filter | ||
150 | * | ||
151 | * Currently unimplemented as no filters use this yet | ||
152 | */ | ||
153 | EAPI Evas_Object *evas_object_filter_param_obj_get (Evas_Object *o, const char *param); | ||
154 | |||
155 | /** | ||
156 | * Set a float parameter of a filter. | ||
157 | * | ||
158 | * This is the same as evas_object_filter_param_int_set(), but for floating | ||
159 | * point values. | ||
160 | * | ||
161 | * @param o Object to set value on. | ||
162 | * @param param Name of the parameter to set. | ||
163 | * @param EINA_TRUE if at least one parameter was set, EINA_FALSE otherwise. | ||
164 | */ | ||
165 | EAPI Eina_Bool evas_object_filter_param_float_set(Evas_Object *o, const char *param, double val); | ||
166 | |||
167 | /** | ||
168 | * Get a float parameter of a filter. | ||
169 | * | ||
170 | * This is the same as evas_object_filter_param_int_get(), but for floating | ||
171 | * point values. | ||
172 | * | ||
173 | * @param o Object to set value on. | ||
174 | * @param param Name of the parameter to set. | ||
175 | * @return The value, or -1 on error. | ||
176 | */ | ||
177 | EAPI double evas_object_filter_param_float_get(Evas_Object *o, const char *param); | ||
178 | |||
179 | #include <stddef.h> // offsetof | ||
180 | |||
181 | #include "evas_common.h" | ||
182 | #include "evas_private.h" | ||
183 | |||
184 | #include <assert.h> | ||
185 | /* disable neon - even after fixes: | ||
186 | * Error: ARM register expected -- vdup.u32 q14,$0xff000000' | ||
187 | * not going to fix now | ||
188 | #ifdef BUILD_NEON | ||
189 | # define BUILD_NEON0 1 | ||
190 | #else | ||
191 | # define BUILD_NEON0 0 | ||
192 | #endif | ||
193 | */ | ||
194 | |||
195 | #define BUILD_NEON0 0 | ||
196 | |||
197 | typedef struct Evas_Filter_Info_Blur | ||
198 | { | ||
199 | double quality; | ||
200 | int radius; | ||
201 | } Evas_Filter_Info_Blur; | ||
202 | |||
203 | typedef struct Evas_Filter_Info_GreyScale | ||
204 | { | ||
205 | double r,g,b; | ||
206 | } Evas_Filter_Info_GreyScale; | ||
207 | |||
208 | typedef struct Evas_Filter_Info_Brightness | ||
209 | { | ||
210 | double adjust; | ||
211 | } Evas_Filter_Info_Brightness; | ||
212 | |||
213 | typedef struct Evas_Filter_Info_Contrast | ||
214 | { | ||
215 | double adjust; | ||
216 | } Evas_Filter_Info_Contrast; | ||
217 | |||
218 | typedef int (*Filter_Size_FN)(Evas_Filter_Info *,int,int,int*,int*,Eina_Bool); | ||
219 | typedef uint8_t *(*Key_FN)(const Evas_Filter_Info *, uint32_t *); | ||
220 | |||
221 | struct fieldinfo | ||
222 | { | ||
223 | const char *field; | ||
224 | int type; | ||
225 | size_t offset; | ||
226 | }; | ||
227 | |||
228 | struct filterinfo | ||
229 | { | ||
230 | Evas_Software_Filter_Fn filter; | ||
231 | const size_t datasize; | ||
232 | Filter_Size_FN sizefn; | ||
233 | Key_FN keyfn; | ||
234 | Eina_Bool alwaysalpha; | ||
235 | }; | ||
236 | |||
237 | enum | ||
238 | { | ||
239 | TYPE_INT, | ||
240 | TYPE_FLOAT | ||
241 | }; | ||
242 | |||
243 | static int blur_size_get(Evas_Filter_Info*, int, int, int *, int *, Eina_Bool); | ||
244 | static uint8_t *gaussian_key_get(const Evas_Filter_Info *, uint32_t *); | ||
245 | |||
246 | static Eina_Bool gaussian_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*); | ||
247 | static Eina_Bool negation_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*); | ||
248 | static Eina_Bool sepia_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*); | ||
249 | static Eina_Bool greyscale_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*); | ||
250 | static Eina_Bool brightness_filter(Evas_Filter_Info*, RGBA_Image*, RGBA_Image*); | ||
251 | static Eina_Bool contrast_filter(Evas_Filter_Info *, RGBA_Image*, RGBA_Image*); | ||
252 | |||
253 | struct filterinfo filterinfo[] = | ||
254 | { | ||
255 | /* None */ | ||
256 | { NULL, 0, NULL, NULL, EINA_FALSE}, | ||
257 | /* Blur */ | ||
258 | { gaussian_filter, sizeof(Evas_Filter_Info_Blur), blur_size_get, gaussian_key_get, EINA_TRUE }, | ||
259 | /* Negation */ | ||
260 | { negation_filter, 0, NULL, NULL, EINA_FALSE }, | ||
261 | /* Sepia */ | ||
262 | { sepia_filter, 0, NULL, NULL, EINA_FALSE }, | ||
263 | /* Greyscale */ | ||
264 | { greyscale_filter, sizeof(Evas_Filter_Info_GreyScale), NULL, NULL, EINA_FALSE }, | ||
265 | /* Brightness */ | ||
266 | { brightness_filter, sizeof(Evas_Filter_Info_Brightness), NULL, NULL, EINA_FALSE }, | ||
267 | /* Contrast */ | ||
268 | { contrast_filter, sizeof(Evas_Filter_Info_Contrast), NULL, NULL, EINA_FALSE}, | ||
269 | }; | ||
270 | |||
271 | |||
272 | static struct fieldinfo blurfields[] = | ||
273 | { | ||
274 | { "quality", TYPE_FLOAT, offsetof(Evas_Filter_Info_Blur, quality) }, | ||
275 | { "radius", TYPE_INT, offsetof(Evas_Filter_Info_Blur, radius) }, | ||
276 | { NULL, 0, 0 }, | ||
277 | }; | ||
278 | |||
279 | static struct fieldinfo greyfields[] = | ||
280 | { | ||
281 | { "red", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) }, | ||
282 | { "green", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) }, | ||
283 | { "blue", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) }, | ||
284 | |||
285 | { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, r) }, | ||
286 | { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, g) }, | ||
287 | { "all", TYPE_FLOAT, offsetof(Evas_Filter_Info_GreyScale, b) }, | ||
288 | { NULL, 0, 0 }, | ||
289 | }; | ||
290 | |||
291 | static struct fieldinfo brightnessfields[] = | ||
292 | { | ||
293 | { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Brightness, adjust) }, | ||
294 | { NULL, 0, 0 }, | ||
295 | }; | ||
296 | |||
297 | static struct fieldinfo contrastfields[] = | ||
298 | { | ||
299 | { "adjust", TYPE_FLOAT, offsetof(Evas_Filter_Info_Contrast, adjust) }, | ||
300 | { NULL, 0, 0 }, | ||
301 | }; | ||
302 | |||
303 | static struct fieldinfo *filterfields[] = | ||
304 | { | ||
305 | NULL, | ||
306 | blurfields, | ||
307 | NULL, | ||
308 | NULL, | ||
309 | greyfields, | ||
310 | brightnessfields, | ||
311 | contrastfields, | ||
312 | }; | ||
313 | |||
314 | static Evas_Filter_Info *filter_alloc(Evas_Object *o); | ||
315 | |||
316 | EAPI Eina_Bool | ||
317 | evas_object_filter_mode_set(Evas_Object *o, Evas_Filter_Mode mode) | ||
318 | { | ||
319 | Evas_Filter_Info *info; | ||
320 | |||
321 | MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ); | ||
322 | return EINA_FALSE; | ||
323 | MAGIC_CHECK_END(); | ||
324 | |||
325 | if ((mode != EVAS_FILTER_MODE_OBJECT) && (mode != EVAS_FILTER_MODE_BELOW)) | ||
326 | return EINA_FALSE; | ||
327 | |||
328 | if (!o->filter) | ||
329 | { | ||
330 | filter_alloc(o); | ||
331 | } | ||
332 | if (!o->filter) return EINA_FALSE; | ||
333 | info = o->filter; | ||
334 | |||
335 | if (info->mode == mode) return EINA_TRUE; /* easy case */ | ||
336 | info->mode = mode; | ||
337 | info->dirty = 1; | ||
338 | return EINA_TRUE; | ||
339 | } | ||
340 | |||
341 | EAPI Evas_Filter_Mode | ||
342 | evas_object_filter_mode_get(Evas_Object *o) | ||
343 | { | ||
344 | MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ); | ||
345 | return EVAS_FILTER_MODE_OBJECT; | ||
346 | MAGIC_CHECK_END(); | ||
347 | |||
348 | if (!o->filter) return EVAS_FILTER_MODE_OBJECT; | ||
349 | return o->filter->mode; | ||
350 | } | ||
351 | |||
352 | EAPI Eina_Bool | ||
353 | evas_object_filter_set(Evas_Object *o, Evas_Filter filter) | ||
354 | { | ||
355 | Evas_Filter_Info *info; | ||
356 | struct filterinfo *finfo; | ||
357 | |||
358 | MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ); | ||
359 | return EINA_FALSE; | ||
360 | MAGIC_CHECK_END(); | ||
361 | |||
362 | /* force filter to be signed: else gcc complains, but enums may always be | ||
363 | * signed */ | ||
364 | if (((int)filter < (int)EVAS_FILTER_NONE) || (filter > EVAS_FILTER_LAST)) | ||
365 | return EINA_FALSE; | ||
366 | |||
367 | /* Don't alloc on no-op */ | ||
368 | if (!o-filter && filter == EVAS_FILTER_NONE) return EINA_TRUE; | ||
369 | |||
370 | if (!o->filter) filter_alloc(o); | ||
371 | if (!o->filter) return EINA_FALSE; | ||
372 | |||
373 | info = o->filter; | ||
374 | |||
375 | if (info->filter == filter) return EINA_TRUE; | ||
376 | |||
377 | finfo = filterinfo + filter; | ||
378 | info->filter = filter; | ||
379 | info->dirty = 1; | ||
380 | if (info->data) | ||
381 | { | ||
382 | if (info->data_free) | ||
383 | info->data_free(info->data); | ||
384 | else | ||
385 | free(info->data); | ||
386 | } | ||
387 | info->datalen = finfo->datasize; | ||
388 | if (finfo->datasize) | ||
389 | { | ||
390 | info->data = calloc(1, finfo->datasize); | ||
391 | if (!info->data) | ||
392 | { | ||
393 | o->filter = EVAS_FILTER_NONE; | ||
394 | return EINA_FALSE; | ||
395 | } | ||
396 | } | ||
397 | else | ||
398 | info->data = NULL; | ||
399 | info->data_free = NULL; | ||
400 | |||
401 | return EINA_TRUE; | ||
402 | } | ||
403 | |||
404 | EAPI Evas_Filter | ||
405 | evas_object_filter_get(Evas_Object *o) | ||
406 | { | ||
407 | MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ); | ||
408 | return EVAS_FILTER_NONE; | ||
409 | MAGIC_CHECK_END(); | ||
410 | |||
411 | if (!o->filter) return EVAS_FILTER_NONE; | ||
412 | return o->filter->filter; | ||
413 | } | ||
414 | |||
415 | EAPI Eina_Bool | ||
416 | evas_object_filter_param_int_set(Evas_Object *o, const char *param, int val) | ||
417 | { | ||
418 | char *data; | ||
419 | const struct fieldinfo *fields; | ||
420 | Eina_Bool found; | ||
421 | int i; | ||
422 | |||
423 | MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ); | ||
424 | return EINA_FALSE; | ||
425 | MAGIC_CHECK_END(); | ||
426 | |||
427 | if ((!o->filter) || (!o->filter->data)) return EINA_FALSE; | ||
428 | |||
429 | fields = filterfields[o->filter->filter]; | ||
430 | data = o->filter->data; | ||
431 | found = EINA_FALSE; | ||
432 | for (i = 0; fields[i].field; i++) | ||
433 | { | ||
434 | if (!strcmp(fields[i].field, param)) | ||
435 | { | ||
436 | if (fields[i].type != TYPE_INT) continue; | ||
437 | *(int *)(data + fields[i].offset) = val; | ||
438 | o->filter->dirty = 1; | ||
439 | evas_object_change(o); | ||
440 | found = EINA_TRUE; | ||
441 | } | ||
442 | } | ||
443 | return found; | ||
444 | } | ||
445 | |||
446 | EAPI int | ||
447 | evas_object_filter_param_int_get(Evas_Object *o, const char *param) | ||
448 | { | ||
449 | char *data; | ||
450 | const struct fieldinfo *fields; | ||
451 | int val; | ||
452 | int i; | ||
453 | |||
454 | MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ); | ||
455 | return -1; | ||
456 | MAGIC_CHECK_END(); | ||
457 | |||
458 | if ((!o->filter) || (!o->filter->data)) return -1; | ||
459 | |||
460 | fields = filterfields[o->filter->filter]; | ||
461 | if (!fields) return -1; | ||
462 | data = o->filter->data; | ||
463 | |||
464 | for (i = 0; fields[i].field; i++) | ||
465 | { | ||
466 | if (!strcmp(fields[i].field, param)) | ||
467 | { | ||
468 | if (fields[i].type != TYPE_INT) continue; | ||
469 | val = *(int *)(data + fields[i].offset); | ||
470 | return val; | ||
471 | } | ||
472 | } | ||
473 | return -1; | ||
474 | } | ||
475 | |||
476 | EAPI Eina_Bool | ||
477 | evas_object_filter_param_str_set(Evas_Object *o __UNUSED__, | ||
478 | const char *param __UNUSED__, | ||
479 | const char *val __UNUSED__) | ||
480 | { | ||
481 | return EINA_FALSE; | ||
482 | } | ||
483 | |||
484 | EAPI const char * | ||
485 | evas_object_filter_param_str_get(Evas_Object *o __UNUSED__, | ||
486 | const char *param __UNUSED__) | ||
487 | { | ||
488 | return NULL; | ||
489 | } | ||
490 | |||
491 | EAPI Eina_Bool | ||
492 | evas_object_filter_param_obj_set(Evas_Object *o __UNUSED__, | ||
493 | const char *param __UNUSED__, | ||
494 | Evas_Object *val __UNUSED__) | ||
495 | { | ||
496 | return EINA_FALSE; | ||
497 | } | ||
498 | |||
499 | EAPI Evas_Object * | ||
500 | evas_object_filter_param_obj_get(Evas_Object *o __UNUSED__, | ||
501 | const char *param __UNUSED__) | ||
502 | { | ||
503 | return NULL; | ||
504 | } | ||
505 | |||
506 | EAPI Eina_Bool | ||
507 | evas_object_filter_param_float_set(Evas_Object *o, const char *param, | ||
508 | double val) | ||
509 | { | ||
510 | char *data; | ||
511 | const struct fieldinfo *fields; | ||
512 | int i; | ||
513 | Eina_Bool rv; | ||
514 | |||
515 | MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ); | ||
516 | return EINA_FALSE; | ||
517 | MAGIC_CHECK_END(); | ||
518 | |||
519 | if ((!o->filter) || (!o->filter->data)) return EINA_FALSE; | ||
520 | |||
521 | rv = EINA_FALSE; | ||
522 | fields = filterfields[o->filter->filter]; | ||
523 | if (!fields) return EINA_FALSE; | ||
524 | |||
525 | data = o->filter->data; | ||
526 | |||
527 | for (i = 0; fields[i].field; i++) | ||
528 | { | ||
529 | if (!strcmp(fields[i].field, param)) | ||
530 | { | ||
531 | if (fields[i].type != TYPE_FLOAT) continue; | ||
532 | *(double *)(data + fields[i].offset) = val; | ||
533 | o->filter->dirty = 1; | ||
534 | o->changed = 1; | ||
535 | evas_object_change(o); | ||
536 | rv = EINA_TRUE; | ||
537 | } | ||
538 | } | ||
539 | return rv; | ||
540 | } | ||
541 | |||
542 | EAPI double | ||
543 | evas_object_filter_param_float_get(Evas_Object *o, const char *param) | ||
544 | { | ||
545 | char *data; | ||
546 | const struct fieldinfo *fields; | ||
547 | double val; | ||
548 | int i; | ||
549 | |||
550 | MAGIC_CHECK(o, Evas_Object, MAGIC_OBJ); | ||
551 | return -1; | ||
552 | MAGIC_CHECK_END(); | ||
553 | |||
554 | if ((!o->filter) || (!o->filter->data)) return -1; | ||
555 | |||
556 | fields = filterfields[o->filter->filter]; | ||
557 | if (!fields) return -1; | ||
558 | data = o->filter->data; | ||
559 | |||
560 | for (i = 0; fields[i].field; i++) | ||
561 | { | ||
562 | if (!strcmp(fields[i].field, param)) | ||
563 | { | ||
564 | if (fields[i].type != TYPE_FLOAT) continue; | ||
565 | val = *(double *)(data + fields[i].offset); | ||
566 | return val; | ||
567 | } | ||
568 | } | ||
569 | return -1; | ||
570 | } | ||
571 | |||
572 | |||
573 | |||
574 | |||
575 | |||
576 | /* | ||
577 | * Internal call | ||
578 | */ | ||
579 | int | ||
580 | evas_filter_get_size(Evas_Filter_Info *info, int inw, int inh, | ||
581 | int *outw, int *outh, Eina_Bool inv) | ||
582 | { | ||
583 | if (!info) return -1; | ||
584 | if ((!outw) && (!outh)) return 0; | ||
585 | |||
586 | if (filterinfo[info->filter].sizefn) | ||
587 | return filterinfo[info->filter].sizefn(info, inw, inh, outw, outh, inv); | ||
588 | |||
589 | if (outw) *outw = inw; | ||
590 | if (outh) *outh = inh; | ||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | Eina_Bool | ||
595 | evas_filter_always_alpha(Evas_Filter_Info *info) | ||
596 | { | ||
597 | if (!info) return EINA_FALSE; | ||
598 | return filterinfo[info->filter].alwaysalpha; | ||
599 | } | ||
600 | |||
601 | /* | ||
602 | * Another internal call: | ||
603 | * Given a filterinfo, generate a unique key for it | ||
604 | * | ||
605 | * For simple filters, it's just the filter type. | ||
606 | * for more complex filters, it's the type, with it's params. | ||
607 | * | ||
608 | * Note management of the key data is up to the caller, that is it should | ||
609 | * probably be freed after use. | ||
610 | * | ||
611 | * Note the automatic fallback generation places the single byte at the end so | ||
612 | * the memcpy will be aligned. Micro-optimisations FTW! | ||
613 | * | ||
614 | * @param info Filter info to generate from | ||
615 | * @param len Length of the buffer returned. | ||
616 | * @return key Key buffer | ||
617 | */ | ||
618 | uint8_t * | ||
619 | evas_filter_key_get(const Evas_Filter_Info *info, uint32_t *lenp) | ||
620 | { | ||
621 | struct filterinfo *finfo; | ||
622 | uint8_t *key; | ||
623 | int len; | ||
624 | |||
625 | if (!info) return NULL; | ||
626 | |||
627 | finfo = filterinfo + info->filter; | ||
628 | if (finfo->keyfn) return finfo->keyfn(info, lenp); | ||
629 | |||
630 | len = 1 + finfo->datasize; | ||
631 | key = malloc(len); | ||
632 | if (!key) return NULL; | ||
633 | if (finfo->datasize) memcpy(key, info->data, finfo->datasize); | ||
634 | key[finfo->datasize] = info->filter; | ||
635 | if (lenp) *lenp = len; | ||
636 | return key; | ||
637 | } | ||
638 | |||
639 | Evas_Software_Filter_Fn | ||
640 | evas_filter_software_get(Evas_Filter_Info *info) | ||
641 | { | ||
642 | return filterinfo[info->filter].filter; | ||
643 | } | ||
644 | |||
645 | void | ||
646 | evas_filter_free(Evas_Object *o) | ||
647 | { | ||
648 | if (!o->filter) return; | ||
649 | if (o->filter->key) free(o->filter->key); | ||
650 | free(o->filter); | ||
651 | o->filter = NULL; | ||
652 | } | ||
653 | |||
654 | |||
655 | |||
656 | |||
657 | /* | ||
658 | * Private calls | ||
659 | */ | ||
660 | static Evas_Filter_Info * | ||
661 | filter_alloc(Evas_Object *o) | ||
662 | { | ||
663 | Evas_Filter_Info *info; | ||
664 | |||
665 | if (!o) return NULL; | ||
666 | info = calloc(1,sizeof(struct Evas_Filter_Info)); | ||
667 | if (!info) return NULL; | ||
668 | info->dirty = 1; | ||
669 | info->filter = EVAS_FILTER_NONE; | ||
670 | info->mode = EVAS_FILTER_MODE_OBJECT; | ||
671 | info->datalen = 0; | ||
672 | |||
673 | o->filter = info; | ||
674 | |||
675 | return info; | ||
676 | } | ||
677 | |||
678 | static int | ||
679 | blur_size_get(Evas_Filter_Info *info, int inw, int inh, int *outw, int *outh, | ||
680 | Eina_Bool inv) | ||
681 | { | ||
682 | Evas_Filter_Info_Blur *blur = info->data; | ||
683 | |||
684 | if (inv) | ||
685 | { | ||
686 | if (outw) *outw = MAX(inw - (blur->radius * 2), 0); | ||
687 | if (outh) *outh = MAX(inh - (blur->radius * 2), 0); | ||
688 | } | ||
689 | else | ||
690 | { | ||
691 | if (outw) *outw = inw + (blur->radius * 2); | ||
692 | if (outh) *outh = inh + (blur->radius * 2); | ||
693 | } | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /* | ||
698 | * Generate a key for the Gaussian generator. | ||
699 | * | ||
700 | * The size is: | ||
701 | * - 1 byte for the type (blur) | ||
702 | * - 1 byte for the quality (0-1 -> 0-255) | ||
703 | * - 2 bytes for radius (max is 508 anyway) | ||
704 | * | ||
705 | * @param info Filter info | ||
706 | * @param len Length of the returned buffer | ||
707 | * @return new buffer | ||
708 | */ | ||
709 | static uint8_t * | ||
710 | gaussian_key_get(const Evas_Filter_Info *info, uint32_t *lenp) | ||
711 | { | ||
712 | struct Evas_Filter_Info_Blur *blur; | ||
713 | uint8_t *key; | ||
714 | |||
715 | if ((!info) || (!info->data)) return NULL; | ||
716 | blur = info->data; | ||
717 | |||
718 | if (lenp) *lenp = 4; | ||
719 | key = malloc(4); | ||
720 | if (!key) return NULL; | ||
721 | key[0] = EVAS_FILTER_BLUR; | ||
722 | key[1] = blur->quality * 255; | ||
723 | key[2] = blur->radius >> 8; | ||
724 | key[3] = blur->radius; | ||
725 | |||
726 | return key; | ||
727 | } | ||
728 | |||
729 | |||
730 | |||
731 | |||
732 | |||
733 | |||
734 | |||
735 | |||
736 | |||
737 | |||
738 | |||
739 | |||
740 | |||
741 | |||
742 | |||
743 | |||
744 | |||
745 | |||
746 | |||
747 | /** | ||
748 | * Software implementations | ||
749 | */ | ||
750 | #define all(OP, A, R, G, B, W, I) \ | ||
751 | do { \ | ||
752 | A OP A_VAL(I) * W; \ | ||
753 | R OP R_VAL(I) * W; \ | ||
754 | G OP G_VAL(I) * W; \ | ||
755 | B OP B_VAL(I) * W; \ | ||
756 | } while (0) | ||
757 | #define wavg(x,n) (((x) / (n)) & 0xff) | ||
758 | #define wavgd(x,n) ((uint32_t)((x) / (n)) & 0xff) | ||
759 | |||
760 | typedef int (*FilterH)(int, uint32_t *, int, uint32_t *); | ||
761 | typedef int (*FilterV)(int, uint32_t *, int, int, uint32_t *); | ||
762 | |||
763 | static int gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out); | ||
764 | static int gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out); | ||
765 | static int gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out); | ||
766 | static int gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out); | ||
767 | static int gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out); | ||
768 | static int gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out); | ||
769 | static const uint32_t *gaussian_row_get(int row, int *npoints, uint32_t *weight); | ||
770 | static const uint64_t *gaussian_row_get64(int row, int *npoints, uint64_t *weight); | ||
771 | static const double *gaussian_row_getd(int row, int *npoints, double *weight); | ||
772 | |||
773 | static Eina_Bool | ||
774 | gaussian_filter(Evas_Filter_Info *filter, RGBA_Image *src, RGBA_Image *dst) | ||
775 | { | ||
776 | int i; | ||
777 | uint32_t nw, nh; | ||
778 | uint32_t *in, *tmp, *out; | ||
779 | FilterV filter_v = gaussian_filter_v; | ||
780 | FilterH filter_h = gaussian_filter_h; | ||
781 | Evas_Filter_Info_Blur *blur; | ||
782 | int w, h; | ||
783 | |||
784 | blur = filter->data; | ||
785 | |||
786 | /* Use 64 bit version if we are going to overflow */ | ||
787 | if (blur->radius > 508) /** too big for doubles: Bail out */ | ||
788 | return EINA_FALSE; | ||
789 | else if (blur->radius > 28) | ||
790 | { | ||
791 | filter_v = gaussian_filter_vd; | ||
792 | filter_h = gaussian_filter_hd; | ||
793 | } | ||
794 | else if (blur->radius > 12) | ||
795 | { | ||
796 | filter_v = gaussian_filter_v64; | ||
797 | filter_h = gaussian_filter_h64; | ||
798 | } | ||
799 | |||
800 | w = src->cache_entry.w; | ||
801 | h = src->cache_entry.h; | ||
802 | in = src->image.data; | ||
803 | |||
804 | if (!in) return EINA_FALSE; | ||
805 | |||
806 | nw = w + (2 * blur->radius); | ||
807 | nh = h + (2 * blur->radius); | ||
808 | |||
809 | out = dst->image.data; | ||
810 | if (!out) return EINA_FALSE; | ||
811 | tmp = malloc(nw * h * sizeof(uint32_t)); | ||
812 | |||
813 | for (i = 0; i < h; i++) | ||
814 | filter_h(blur->radius,in + (i * w), w, tmp + (i * nw)); | ||
815 | |||
816 | for (i = 0; i < (int)nw; i++) | ||
817 | filter_v(blur->radius,tmp + i, h, nw, out + i); | ||
818 | |||
819 | free(tmp); | ||
820 | return EINA_TRUE; | ||
821 | } | ||
822 | |||
823 | /* Blur only horizontally */ | ||
824 | static int | ||
825 | gaussian_filter_h(int rad, uint32_t *in, int w, uint32_t *out) | ||
826 | { | ||
827 | const uint32_t *points; | ||
828 | int npoints = 0; | ||
829 | uint32_t weight = 0; | ||
830 | int i = 0, k = 0; | ||
831 | uint32_t r, g, b, a; | ||
832 | |||
833 | /* Get twice the radius: even rows have 1 element */ | ||
834 | points = gaussian_row_get(rad * 2, &npoints, &weight); | ||
835 | for (i = -rad; i < (w + rad); i++) | ||
836 | { | ||
837 | r = g = b = a = 0; | ||
838 | for (k = -rad; k <= rad; k++) | ||
839 | { | ||
840 | if ((k + i) < 0) continue; | ||
841 | if ((k + i) >= w) continue; | ||
842 | all(+=, a, r, g, b, points[k + rad], in + k + i); | ||
843 | } | ||
844 | *(out) = ARGB_JOIN(wavg(a, weight), | ||
845 | wavg(r, weight), | ||
846 | wavg(g, weight), | ||
847 | wavg(b, weight)); | ||
848 | out++; | ||
849 | } | ||
850 | return 0; | ||
851 | } | ||
852 | |||
853 | /* Blur only horizontally */ | ||
854 | static int | ||
855 | gaussian_filter_hd(int rad, uint32_t *in, int w, uint32_t *out) | ||
856 | { | ||
857 | const double *points; | ||
858 | int npoints = 0; | ||
859 | double weight = 0.0; | ||
860 | int i = 0, k = 0; | ||
861 | double r, g, b, a; | ||
862 | |||
863 | /* Get twice the radius: even rows have 1 element */ | ||
864 | points = gaussian_row_getd(rad * 2, &npoints, &weight); | ||
865 | for (i = -rad; i < (w + rad); i++) | ||
866 | { | ||
867 | r = g = b = a = 0; | ||
868 | for (k = -rad; k <= rad; k++) | ||
869 | { | ||
870 | if ((k + i) < 0) continue; | ||
871 | if ((k + i) >= w) continue; | ||
872 | all(+=, a, r, g, b, points[k + rad], in + k + i); | ||
873 | } | ||
874 | *(out) = ARGB_JOIN(wavgd(a, weight), | ||
875 | wavgd(r, weight), | ||
876 | wavgd(g, weight), | ||
877 | wavgd(b, weight)); | ||
878 | out++; | ||
879 | } | ||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | |||
884 | /* Blur only horizontally */ | ||
885 | static int | ||
886 | gaussian_filter_h64(int rad, uint32_t *in, int w, uint32_t *out) | ||
887 | { | ||
888 | const uint64_t *points; | ||
889 | int npoints = 0; | ||
890 | uint64_t weight = 0; | ||
891 | int i = 0, k = 0; | ||
892 | uint64_t r, g, b, a; | ||
893 | |||
894 | /* Get twice the radius: even rows have 1 element */ | ||
895 | points = gaussian_row_get64(rad * 2, &npoints, &weight); | ||
896 | for (i = -rad ; i < w + rad; i ++){ | ||
897 | r = g = b = a = 0; | ||
898 | for (k = -rad ; k <= rad ; k ++){ | ||
899 | if ((k + i) < 0) continue; | ||
900 | if ((k + i) >= w) continue; | ||
901 | all(+=, a, r, g, b, points[k + rad], in + k + i); | ||
902 | } | ||
903 | *(out) = ARGB_JOIN(wavg(a, weight), | ||
904 | wavg(r, weight), | ||
905 | wavg(g, weight), | ||
906 | wavg(b, weight)); | ||
907 | out++; | ||
908 | } | ||
909 | return 0; | ||
910 | } | ||
911 | |||
912 | static int | ||
913 | gaussian_filter_v(int rad, uint32_t *in, int h, int skip, uint32_t *out) | ||
914 | { | ||
915 | const uint32_t *points; | ||
916 | int npoints = 0; | ||
917 | uint32_t weight = 0; | ||
918 | int i = 0, k = 0; | ||
919 | uint32_t r, g, b, a; | ||
920 | |||
921 | /* Get twice the radius: even rows have 1 element */ | ||
922 | points = gaussian_row_get(rad * 2, &npoints, &weight); | ||
923 | weight = 0; | ||
924 | for (i = 0; i < npoints; i++) weight += points[i]; | ||
925 | |||
926 | for (i = -rad; i < (h + rad); i++) | ||
927 | { | ||
928 | r = g = b = a = 0; | ||
929 | for (k = -rad; k <= rad; k++) | ||
930 | { | ||
931 | if ((k + i) < 0) continue; | ||
932 | if ((k + i) >= h) continue; | ||
933 | all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i))); | ||
934 | } | ||
935 | *(out) = ARGB_JOIN(wavg(a, weight), | ||
936 | wavg(r, weight), | ||
937 | wavg(g, weight), | ||
938 | wavg(b, weight)); | ||
939 | out += skip; | ||
940 | } | ||
941 | return 0; | ||
942 | } | ||
943 | |||
944 | static int | ||
945 | gaussian_filter_v64(int rad, uint32_t *in, int h, int skip, uint32_t *out) | ||
946 | { | ||
947 | const uint64_t *points; | ||
948 | int npoints = 0; | ||
949 | uint64_t weight; | ||
950 | int i = 0, k = 0; | ||
951 | uint64_t r, g, b, a; | ||
952 | |||
953 | /* Get twice the radius: even rows have 1 element */ | ||
954 | points = gaussian_row_get64(rad * 2, &npoints, &weight); | ||
955 | weight = 0; | ||
956 | for (i = 0; i < npoints; i++) weight += points[i]; | ||
957 | |||
958 | for (i = -rad; i < (h + rad); i++) | ||
959 | { | ||
960 | r = g = b = a = 0; | ||
961 | for (k = -rad ; k <= rad ; k++) | ||
962 | { | ||
963 | if ((k + i) < 0) continue; | ||
964 | if ((k + i) >= h) continue; | ||
965 | all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i))); | ||
966 | } | ||
967 | *(out) = ARGB_JOIN(wavg(a, weight), | ||
968 | wavg(r, weight), | ||
969 | wavg(g, weight), | ||
970 | wavg(b, weight)); | ||
971 | out += skip; | ||
972 | } | ||
973 | return 0; | ||
974 | } | ||
975 | |||
976 | static int | ||
977 | gaussian_filter_vd(int rad, uint32_t *in, int h, int skip, uint32_t *out) | ||
978 | { | ||
979 | const double *points; | ||
980 | int npoints = 0; | ||
981 | double weight = 0.0; | ||
982 | int i = 0, k = 0; | ||
983 | double r, g, b, a; | ||
984 | |||
985 | /* Get twice the radius: even rows have 1 element */ | ||
986 | points = gaussian_row_getd(rad * 2, &npoints, &weight); | ||
987 | weight = 0; | ||
988 | for (i = 0 ; i < npoints ; i ++) weight += points[i]; | ||
989 | |||
990 | for (i = -rad ; i < h + rad; i ++) | ||
991 | { | ||
992 | r = g = b = a = 0; | ||
993 | for (k = -rad ; k <= rad ; k ++) | ||
994 | { | ||
995 | if ((k + i) < 0) continue; | ||
996 | if ((k + i) >= h) continue; | ||
997 | all(+=, a, r, g, b, points[k + rad], in + (skip * (k + i))); | ||
998 | } | ||
999 | *(out) = ARGB_JOIN(wavgd(a, weight), | ||
1000 | wavgd(r, weight), | ||
1001 | wavgd(g, weight), | ||
1002 | wavgd(b, weight)); | ||
1003 | out += skip; | ||
1004 | } | ||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static const uint32_t * | ||
1009 | gaussian_row_get(int row, int *npoints, uint32_t *weight) | ||
1010 | { | ||
1011 | static uint32_t *points = NULL; | ||
1012 | static int last = -1; | ||
1013 | static uint32_t lastweight = -1; | ||
1014 | int c, k; | ||
1015 | |||
1016 | if (row < 0) return NULL; | ||
1017 | |||
1018 | if (npoints) *npoints = row + 1; | ||
1019 | |||
1020 | if (last == row) | ||
1021 | { | ||
1022 | if (weight) *weight = lastweight; | ||
1023 | return points; | ||
1024 | } | ||
1025 | if (points) free(points); | ||
1026 | |||
1027 | points = malloc((row + 1) * sizeof(uint32_t)); | ||
1028 | if (!points) | ||
1029 | { | ||
1030 | last = -1; | ||
1031 | return NULL; | ||
1032 | } | ||
1033 | last = row; | ||
1034 | |||
1035 | c = 1; | ||
1036 | for (k = 0; k <= row; k++) | ||
1037 | { | ||
1038 | points[k] = c; | ||
1039 | c = c * (row - k) / (k + 1); | ||
1040 | } | ||
1041 | |||
1042 | for (k = 0, lastweight = 0; k <= row; k++) lastweight += points[k]; | ||
1043 | if (weight) *weight = lastweight; | ||
1044 | return points; | ||
1045 | } | ||
1046 | |||
1047 | static const uint64_t * | ||
1048 | gaussian_row_get64(int row, int *npoints, uint64_t *weight) | ||
1049 | { | ||
1050 | static uint64_t *points = NULL; | ||
1051 | static int last = -1; | ||
1052 | static uint64_t lastweight = -1; | ||
1053 | uint64_t c; | ||
1054 | int k; | ||
1055 | |||
1056 | if (row < 0) return NULL; | ||
1057 | |||
1058 | if (npoints) *npoints = row + 1; | ||
1059 | if (last == row) | ||
1060 | { | ||
1061 | if (weight) *weight = lastweight; | ||
1062 | return points; | ||
1063 | } | ||
1064 | if (points) free(points); | ||
1065 | |||
1066 | points = malloc((row + 1) * sizeof(uint64_t)); | ||
1067 | if (!points) | ||
1068 | { | ||
1069 | last = -1; | ||
1070 | return NULL; | ||
1071 | } | ||
1072 | last = row; | ||
1073 | |||
1074 | c = 1; | ||
1075 | for (k = 0; k <= row; k++) | ||
1076 | { | ||
1077 | points[k] = c; | ||
1078 | c = c * (row - k) / (k + 1); | ||
1079 | } | ||
1080 | |||
1081 | for (k = 0, lastweight = 0; k <= row; k ++) lastweight += points[k]; | ||
1082 | if (weight) *weight = lastweight; | ||
1083 | |||
1084 | return points; | ||
1085 | } | ||
1086 | |||
1087 | static const double * | ||
1088 | gaussian_row_getd(int row, int *npoints, double *weight) | ||
1089 | { | ||
1090 | static double *points = NULL; | ||
1091 | static int last = -1; | ||
1092 | static double lastweight = -1; | ||
1093 | double c; | ||
1094 | int k; | ||
1095 | |||
1096 | if (row < 0) return NULL; | ||
1097 | |||
1098 | if (last == row) | ||
1099 | { | ||
1100 | if (weight) *weight = lastweight; | ||
1101 | return points; | ||
1102 | } | ||
1103 | |||
1104 | if (points) free(points); | ||
1105 | points = malloc((row + 1) * sizeof(double)); | ||
1106 | if (!points) | ||
1107 | { | ||
1108 | last = -1; | ||
1109 | return NULL; | ||
1110 | } | ||
1111 | last = row; | ||
1112 | |||
1113 | if (npoints) *npoints = row + 1; | ||
1114 | |||
1115 | c = 1; | ||
1116 | for (k = 0; k <= row; k++) | ||
1117 | { | ||
1118 | points[k] = c; | ||
1119 | c = c * (row - k) / (k + 1); | ||
1120 | } | ||
1121 | |||
1122 | for (k = 0, lastweight = 0; k <= row; k++) lastweight += points[k]; | ||
1123 | if (weight) *weight = lastweight; | ||
1124 | |||
1125 | return points; | ||
1126 | } | ||
1127 | |||
1128 | #if BUILD_NEON0 | ||
1129 | static Eina_Bool | ||
1130 | negation_filter_neon(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst) | ||
1131 | { | ||
1132 | uint32_t tmp; | ||
1133 | |||
1134 | if (src->cache_entry.flags.alpha) | ||
1135 | { | ||
1136 | // FIXME: not implemented | ||
1137 | } | ||
1138 | else | ||
1139 | { | ||
1140 | /* No alpha */ | ||
1141 | #define AP "NEG_FILTER_NA" | ||
1142 | asm volatile ( | ||
1143 | |||
1144 | ".fpu neon \n\t" | ||
1145 | "vdup.u32 q14, $0xff000000 \n\t" | ||
1146 | "vmvn.u32 q15, q1 \n\t" | ||
1147 | |||
1148 | // fixme: do check for small loops | ||
1149 | AP"loopinit: \n\t" | ||
1150 | "sub %[tmp], %[e], #31 \n\t" | ||
1151 | |||
1152 | AP"loop: \n\t" | ||
1153 | "vldm %[s]!, {d0,d1,d2,d3} \n\t" | ||
1154 | "vand q2, q0, q15 \n\t" | ||
1155 | "vand q3, q1, q15 \n\t" | ||
1156 | "vand q4, q0, q14 \n\t" | ||
1157 | "vand q5, q1, q14 \n\t" | ||
1158 | // fixme: can i do this with xor | ||
1159 | "cmp %[tmp], %[s] \n\t" | ||
1160 | |||
1161 | "vmvn q6, q2 \n\t" | ||
1162 | "vmvn q7, q3 \n\t" | ||
1163 | |||
1164 | "vorr q0, q6,q4 \n\t" | ||
1165 | "vorr q1, q7,q5 \n\t" | ||
1166 | |||
1167 | "vstm %[d]!, {d0,d1,d2,d3} \n\t" | ||
1168 | |||
1169 | "bhi "AP"loop \n\t" | ||
1170 | |||
1171 | : // no out | ||
1172 | : // input | ||
1173 | [e] "r" (src->image.data+ src->cache_entry.w*src->cache_entry.h), | ||
1174 | [s] "r" (src->image.data), | ||
1175 | [tmp] "r" (tmp), | ||
1176 | [d] "r" (dst->image.data) | ||
1177 | : "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q14", "q15", | ||
1178 | "memory" | ||
1179 | ); | ||
1180 | #undef AP | ||
1181 | } | ||
1182 | return EINA_TRUE; | ||
1183 | } | ||
1184 | #endif | ||
1185 | |||
1186 | static Eina_Bool | ||
1187 | negation_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst) | ||
1188 | { | ||
1189 | uint32_t *in, *out; | ||
1190 | int i,j; | ||
1191 | int w,h; | ||
1192 | uint32_t a; | ||
1193 | uint8_t r,g,b; | ||
1194 | |||
1195 | #if BUILD_NEON0 | ||
1196 | if (evas_common_cpu_has_feature(CPU_FEATURE_NEON) && | ||
1197 | (!src->cache_entry.flags.alpha)) | ||
1198 | return negation_filter_neon(info, src, dst); | ||
1199 | #endif | ||
1200 | |||
1201 | in = src->image.data; | ||
1202 | out = dst->image.data; | ||
1203 | w = src->cache_entry.w; | ||
1204 | h = src->cache_entry.h; | ||
1205 | |||
1206 | if (src->cache_entry.flags.alpha) | ||
1207 | { | ||
1208 | for (i = 0; i < h; i++) | ||
1209 | { | ||
1210 | for (j = 0; j < w; j++) | ||
1211 | { | ||
1212 | a = A_VAL(in); | ||
1213 | r = R_VAL(in); | ||
1214 | g = G_VAL(in); | ||
1215 | b = B_VAL(in); | ||
1216 | *out = ARGB_JOIN(a, a - r, a - g, a - b); | ||
1217 | out++; | ||
1218 | in++; | ||
1219 | } | ||
1220 | } | ||
1221 | } | ||
1222 | else | ||
1223 | { | ||
1224 | for (i = 0; i < h; i++) | ||
1225 | { | ||
1226 | for (j = 0; j < w; j++) | ||
1227 | { | ||
1228 | a = A_VAL(in); | ||
1229 | r = R_VAL(in); | ||
1230 | g = G_VAL(in); | ||
1231 | b = B_VAL(in); | ||
1232 | *out = ARGB_JOIN(a, ~r, ~g, ~b); | ||
1233 | out++; | ||
1234 | in++; | ||
1235 | } | ||
1236 | } | ||
1237 | } | ||
1238 | return EINA_TRUE; | ||
1239 | info = NULL; | ||
1240 | } | ||
1241 | |||
1242 | static Eina_Bool | ||
1243 | sepia_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst) | ||
1244 | { | ||
1245 | uint32_t *in, *out; | ||
1246 | int i, j; | ||
1247 | int w, h; | ||
1248 | uint32_t a, r, g, b, nr, ng, nb; | ||
1249 | |||
1250 | in = src->image.data; | ||
1251 | out = dst->image.data; | ||
1252 | w = src->cache_entry.w; | ||
1253 | h = src->cache_entry.h; | ||
1254 | |||
1255 | for (i = 0; i < h; i++) | ||
1256 | { | ||
1257 | for (j = 0; j < w; j++) | ||
1258 | { | ||
1259 | a = A_VAL(in); | ||
1260 | r = R_VAL(in); | ||
1261 | g = G_VAL(in); | ||
1262 | b = B_VAL(in); | ||
1263 | nr = ((uint32_t)((r * 0.393) + (g * 0.769) + (b * 0.189))); | ||
1264 | ng = ((uint32_t)((r * 0.349) + (g * 0.686) + (b * 0.168))); | ||
1265 | nb = ((uint32_t)((r * 0.272) + (g * 0.534) + (b * 0.131))); | ||
1266 | if (nr > 255) nr = 255; | ||
1267 | if (ng > 255) ng = 255; | ||
1268 | if (nb > 255) nb = 255; | ||
1269 | *out = ARGB_JOIN(a, nr, ng, nb); | ||
1270 | out++; | ||
1271 | in++; | ||
1272 | } | ||
1273 | } | ||
1274 | |||
1275 | return EINA_TRUE; | ||
1276 | |||
1277 | } | ||
1278 | |||
1279 | static Eina_Bool | ||
1280 | greyscale_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst) | ||
1281 | { | ||
1282 | uint32_t *in, *out; | ||
1283 | int i, j; | ||
1284 | int w, h; | ||
1285 | uint32_t cur; | ||
1286 | uint32_t a, r, g, b; | ||
1287 | |||
1288 | in = src->image.data; | ||
1289 | out = dst->image.data; | ||
1290 | w = src->cache_entry.w; | ||
1291 | h = src->cache_entry.h; | ||
1292 | |||
1293 | if (src->cache_entry.flags.alpha) | ||
1294 | { | ||
1295 | for (i = 0; i < h; i++) | ||
1296 | { | ||
1297 | for (j = 0; j < w; j++) | ||
1298 | { | ||
1299 | a = A_VAL(in); | ||
1300 | r = R_VAL(in); | ||
1301 | g = G_VAL(in); | ||
1302 | b = B_VAL(in); | ||
1303 | cur = (r * 0.3) + (g * 0.59) + (b * 0.11); | ||
1304 | *out = ARGB_JOIN(a, r, g, b); | ||
1305 | out++; | ||
1306 | in++; | ||
1307 | } | ||
1308 | } | ||
1309 | } | ||
1310 | else | ||
1311 | { | ||
1312 | for (i = 0 ; i < h ; i ++) | ||
1313 | { | ||
1314 | for (j = 0; j < w ; j ++) | ||
1315 | { | ||
1316 | r = R_VAL(in); | ||
1317 | g = G_VAL(in); | ||
1318 | b = B_VAL(in); | ||
1319 | cur = r * 0.3 + g * 0.59 + b * 0.11; | ||
1320 | *out = ARGB_JOIN(255, r, g, b); | ||
1321 | out++; | ||
1322 | in++; | ||
1323 | } | ||
1324 | } | ||
1325 | } | ||
1326 | return EINA_TRUE; | ||
1327 | } | ||
1328 | |||
1329 | static Eina_Bool | ||
1330 | brightness_filter(Evas_Filter_Info *info, RGBA_Image *src, RGBA_Image *dst) | ||
1331 | { | ||
1332 | uint32_t *in, *out; | ||
1333 | int i, j; | ||
1334 | int w, h; | ||
1335 | int a,r,g,b; | ||
1336 | int delta; | ||
1337 | int adjdelta; | ||
1338 | Evas_Filter_Info_Brightness *bness; | ||
1339 | |||
1340 | in = src->image.data; | ||
1341 | out = dst->image.data; | ||
1342 | w = src->cache_entry.w; | ||
1343 | h = src->cache_entry.h; | ||
1344 | bness = info->data; | ||
1345 | |||
1346 | delta = bness->adjust * 255; | ||
1347 | if (delta > 255) | ||
1348 | delta = 255; | ||
1349 | else if (delta < -255) | ||
1350 | delta = -255; | ||
1351 | |||
1352 | /* Note we could optimise the -255, 0 and 255 cases, but why would people | ||
1353 | * be doing that */ | ||
1354 | if (delta >= 0) | ||
1355 | { | ||
1356 | for (i = 0; i < h; i++) | ||
1357 | { | ||
1358 | for (j = 0; j < w; j++) | ||
1359 | { | ||
1360 | a = A_VAL(in); | ||
1361 | r = R_VAL(in); | ||
1362 | g = G_VAL(in); | ||
1363 | b = B_VAL(in); | ||
1364 | adjdelta = (a * delta) >> 8; | ||
1365 | r = MIN(r + adjdelta, a); | ||
1366 | g = MIN(g + adjdelta, a); | ||
1367 | b = MIN(b + adjdelta, a); | ||
1368 | *out = ARGB_JOIN(a, r ,g, b); | ||
1369 | out++; | ||
1370 | in++; | ||
1371 | } | ||
1372 | } | ||
1373 | } | ||
1374 | else | ||
1375 | { | ||
1376 | /* Delta negative */ | ||
1377 | for (i = 0; i < h; i++) | ||
1378 | { | ||
1379 | for (j = 0; j < w; j++) | ||
1380 | { | ||
1381 | a = A_VAL(in); | ||
1382 | r = R_VAL(in); | ||
1383 | g = G_VAL(in); | ||
1384 | b = B_VAL(in); | ||
1385 | adjdelta = (a * delta) >> 8; | ||
1386 | r = MAX(r + adjdelta, 0); | ||
1387 | g = MAX(g + adjdelta, 0); | ||
1388 | b = MAX(b + adjdelta, 0); | ||
1389 | *out = ARGB_JOIN(a, r ,g, b); | ||
1390 | out++; | ||
1391 | in++; | ||
1392 | } | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | return EINA_TRUE; | ||
1397 | |||
1398 | } | ||
1399 | |||
1400 | static Eina_Bool | ||
1401 | contrast_filter(Evas_Filter_Info *info __UNUSED__, RGBA_Image *src, RGBA_Image *dst) | ||
1402 | { | ||
1403 | uint32_t *in, *out; | ||
1404 | int i, j; | ||
1405 | int w, h; | ||
1406 | |||
1407 | in = src->image.data; | ||
1408 | out = dst->image.data; | ||
1409 | w = src->cache_entry.w; | ||
1410 | h = src->cache_entry.h; | ||
1411 | |||
1412 | for (i = 0; i < h; i++) | ||
1413 | { | ||
1414 | for (j = 0; j < w; j++) | ||
1415 | { | ||
1416 | // FIXME: not even implemented | ||
1417 | out++; | ||
1418 | in++; | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1422 | return EINA_TRUE; | ||
1423 | |||
1424 | } | ||
1425 | #endif | ||
1426 | |||
1427 | /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/ | ||
diff --git a/libraries/evas/src/lib/canvas/evas_focus.c b/libraries/evas/src/lib/canvas/evas_focus.c new file mode 100644 index 0000000..a1a3bca --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_focus.c | |||
@@ -0,0 +1,59 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* private calls */ | ||
5 | |||
6 | /* local calls */ | ||
7 | |||
8 | /* public calls */ | ||
9 | |||
10 | EAPI void | ||
11 | evas_object_focus_set(Evas_Object *obj, Eina_Bool focus) | ||
12 | { | ||
13 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
14 | return; | ||
15 | MAGIC_CHECK_END(); | ||
16 | |||
17 | _evas_object_event_new(); | ||
18 | |||
19 | if (focus) | ||
20 | { | ||
21 | if (obj->focused) goto end; | ||
22 | if (obj->layer->evas->focused) | ||
23 | evas_object_focus_set(obj->layer->evas->focused, 0); | ||
24 | obj->focused = 1; | ||
25 | obj->layer->evas->focused = obj; | ||
26 | evas_object_event_callback_call(obj, EVAS_CALLBACK_FOCUS_IN, NULL); | ||
27 | evas_event_callback_call(obj->layer->evas, | ||
28 | EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_IN, obj); | ||
29 | } | ||
30 | else | ||
31 | { | ||
32 | if (!obj->focused) goto end; | ||
33 | obj->focused = 0; | ||
34 | obj->layer->evas->focused = NULL; | ||
35 | evas_object_event_callback_call(obj, EVAS_CALLBACK_FOCUS_OUT, NULL); | ||
36 | evas_event_callback_call(obj->layer->evas, | ||
37 | EVAS_CALLBACK_CANVAS_OBJECT_FOCUS_OUT, obj); | ||
38 | } | ||
39 | end: | ||
40 | _evas_post_event_callback_call(obj->layer->evas); | ||
41 | } | ||
42 | |||
43 | EAPI Eina_Bool | ||
44 | evas_object_focus_get(const Evas_Object *obj) | ||
45 | { | ||
46 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
47 | return 0; | ||
48 | MAGIC_CHECK_END(); | ||
49 | return obj->focused; | ||
50 | } | ||
51 | |||
52 | EAPI Evas_Object * | ||
53 | evas_focus_get(const Evas *e) | ||
54 | { | ||
55 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
56 | return NULL; | ||
57 | MAGIC_CHECK_END(); | ||
58 | return e->focused; | ||
59 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_font_dir.c b/libraries/evas/src/lib/canvas/evas_font_dir.c new file mode 100644 index 0000000..e97f7f7 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_font_dir.c | |||
@@ -0,0 +1,1349 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #ifdef HAVE_EVIL | ||
6 | # include <Evil.h> | ||
7 | #endif | ||
8 | |||
9 | #ifdef BUILD_FONT_LOADER_EET | ||
10 | #include <Eet.h> | ||
11 | #endif | ||
12 | |||
13 | #ifdef HAVE_FONTCONFIG | ||
14 | #include <fontconfig/fontconfig.h> | ||
15 | #endif | ||
16 | |||
17 | #include "evas_common.h" | ||
18 | #include "evas_private.h" | ||
19 | |||
20 | /* font dir cache */ | ||
21 | static Eina_Hash *font_dirs = NULL; | ||
22 | static Eina_List *fonts_cache = NULL; | ||
23 | static Eina_List *fonts_zero = NULL; | ||
24 | |||
25 | typedef struct _Fndat Fndat; | ||
26 | |||
27 | struct _Fndat | ||
28 | { | ||
29 | Evas_Font_Description *fdesc; | ||
30 | const char *source; | ||
31 | Evas_Font_Size size; | ||
32 | Evas_Font_Set *font; | ||
33 | int ref; | ||
34 | Font_Rend_Flags wanted_rend; | ||
35 | |||
36 | #ifdef HAVE_FONTCONFIG | ||
37 | FcFontSet *set; | ||
38 | FcPattern *p_nm; | ||
39 | #endif | ||
40 | }; | ||
41 | |||
42 | /* private methods for font dir cache */ | ||
43 | static Eina_Bool font_cache_dir_free(const Eina_Hash *hash, const void *key, void *data, void *fdata); | ||
44 | static Evas_Font_Dir *object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd); | ||
45 | static Evas_Font *object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font); | ||
46 | static Evas_Font *object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font); | ||
47 | static Evas_Font *object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font); | ||
48 | static Evas_Font *object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font); | ||
49 | static Evas_Font_Dir *object_text_font_cache_dir_add(char *dir); | ||
50 | static void object_text_font_cache_dir_del(char *dir, Evas_Font_Dir *fd); | ||
51 | static int evas_object_text_font_string_parse(char *buffer, char dest[14][256]); | ||
52 | |||
53 | #ifdef HAVE_FONTCONFIG | ||
54 | static int fc_init = 0; | ||
55 | #endif | ||
56 | |||
57 | void | ||
58 | evas_font_dir_cache_free(void) | ||
59 | { | ||
60 | if (!font_dirs) return; | ||
61 | |||
62 | eina_hash_foreach(font_dirs, font_cache_dir_free, NULL); | ||
63 | eina_hash_free(font_dirs); | ||
64 | font_dirs = NULL; | ||
65 | |||
66 | #ifdef HAVE_FONTCONFIG | ||
67 | /* this is bad i got a: | ||
68 | * fccache.c:512: FcCacheFini: Assertion fcCacheChains[i] == ((void *)0)' failed. | ||
69 | * | ||
70 | * all i can do for now is shut this puppy down. butthat breaks, so disable | ||
71 | * it as in reality - there is little reason to care about the memory not | ||
72 | * being freed etc. | ||
73 | * | ||
74 | * fc_init--; | ||
75 | * if (fc_init == 0) FcFini(); | ||
76 | */ | ||
77 | #endif | ||
78 | } | ||
79 | |||
80 | const char * | ||
81 | evas_font_dir_cache_find(char *dir, char *font) | ||
82 | { | ||
83 | Evas_Font_Dir *fd = NULL; | ||
84 | |||
85 | if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL); | ||
86 | else fd = eina_hash_find(font_dirs, dir); | ||
87 | fd = object_text_font_cache_dir_update(dir, fd); | ||
88 | if (fd) | ||
89 | { | ||
90 | Evas_Font *fn; | ||
91 | |||
92 | fn = object_text_font_cache_font_find(fd, font); | ||
93 | if (fn) | ||
94 | { | ||
95 | return fn->path; | ||
96 | } | ||
97 | } | ||
98 | return NULL; | ||
99 | } | ||
100 | |||
101 | static Eina_List * | ||
102 | evas_font_set_get(const char *name) | ||
103 | { | ||
104 | Eina_List *fonts = NULL; | ||
105 | char *p; | ||
106 | |||
107 | p = strchr(name, ','); | ||
108 | if (!p) | ||
109 | { | ||
110 | fonts = eina_list_append(fonts, eina_stringshare_add(name)); | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | const char *pp; | ||
115 | char *nm; | ||
116 | |||
117 | pp = name; | ||
118 | while (p) | ||
119 | { | ||
120 | nm = alloca(p - pp + 1); | ||
121 | strncpy(nm, pp, p - pp); | ||
122 | nm[p - pp] = 0; | ||
123 | fonts = eina_list_append(fonts, eina_stringshare_add(nm)); | ||
124 | pp = p + 1; | ||
125 | p = strchr(pp, ','); | ||
126 | if (!p) fonts = eina_list_append(fonts, eina_stringshare_add(pp)); | ||
127 | } | ||
128 | } | ||
129 | return fonts; | ||
130 | } | ||
131 | |||
132 | void | ||
133 | evas_fonts_zero_free(Evas *evas) | ||
134 | { | ||
135 | Fndat *fd; | ||
136 | |||
137 | EINA_LIST_FREE(fonts_zero, fd) | ||
138 | { | ||
139 | if (fd->fdesc) evas_font_desc_unref(fd->fdesc); | ||
140 | if (fd->source) eina_stringshare_del(fd->source); | ||
141 | evas->engine.func->font_free(evas->engine.data.output, fd->font); | ||
142 | #ifdef HAVE_FONTCONFIG | ||
143 | if (fd->set) FcFontSetDestroy(fd->set); | ||
144 | if (fd->p_nm) FcPatternDestroy(fd->p_nm); | ||
145 | #endif | ||
146 | free(fd); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | void | ||
151 | evas_fonts_zero_presure(Evas *evas) | ||
152 | { | ||
153 | Fndat *fd; | ||
154 | |||
155 | while (fonts_zero | ||
156 | && eina_list_count(fonts_zero) > 4) /* 4 is arbitrary */ | ||
157 | { | ||
158 | fd = eina_list_data_get(fonts_zero); | ||
159 | |||
160 | if (fd->ref != 0) break; | ||
161 | fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero); | ||
162 | |||
163 | if (fd->fdesc) evas_font_desc_unref(fd->fdesc); | ||
164 | if (fd->source) eina_stringshare_del(fd->source); | ||
165 | evas->engine.func->font_free(evas->engine.data.output, fd->font); | ||
166 | #ifdef HAVE_FONTCONFIG | ||
167 | if (fd->set) FcFontSetDestroy(fd->set); | ||
168 | if (fd->p_nm) FcPatternDestroy(fd->p_nm); | ||
169 | #endif | ||
170 | free(fd); | ||
171 | |||
172 | if (eina_list_count(fonts_zero) < 5) break; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | void | ||
177 | evas_font_free(Evas *evas, void *font) | ||
178 | { | ||
179 | Eina_List *l; | ||
180 | Fndat *fd; | ||
181 | |||
182 | EINA_LIST_FOREACH(fonts_cache, l, fd) | ||
183 | { | ||
184 | if (fd->font == font) | ||
185 | { | ||
186 | fd->ref--; | ||
187 | if (fd->ref == 0) | ||
188 | { | ||
189 | fonts_cache = eina_list_remove_list(fonts_cache, l); | ||
190 | fonts_zero = eina_list_append(fonts_zero, fd); | ||
191 | } | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | while (fonts_zero | ||
196 | && eina_list_count(fonts_zero) > 42) /* 42 is arbitrary */ | ||
197 | { | ||
198 | fd = eina_list_data_get(fonts_zero); | ||
199 | |||
200 | if (fd->ref != 0) break; | ||
201 | fonts_zero = eina_list_remove_list(fonts_zero, fonts_zero); | ||
202 | |||
203 | if (fd->fdesc) evas_font_desc_unref(fd->fdesc); | ||
204 | if (fd->source) eina_stringshare_del(fd->source); | ||
205 | evas->engine.func->font_free(evas->engine.data.output, fd->font); | ||
206 | #ifdef HAVE_FONTCONFIG | ||
207 | if (fd->set) FcFontSetDestroy(fd->set); | ||
208 | if (fd->p_nm) FcPatternDestroy(fd->p_nm); | ||
209 | #endif | ||
210 | free(fd); | ||
211 | |||
212 | if (eina_list_count(fonts_zero) < 43) break; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static void | ||
217 | evas_font_init(void) | ||
218 | { | ||
219 | static int done = 0; | ||
220 | if (done) return; | ||
221 | done = 1; | ||
222 | #ifdef HAVE_FONTCONFIG | ||
223 | fc_init++; | ||
224 | if (fc_init == 1) | ||
225 | { | ||
226 | FcInit(); | ||
227 | FcConfigEnableHome(1); | ||
228 | } | ||
229 | #endif | ||
230 | } | ||
231 | |||
232 | #ifdef HAVE_FONTCONFIG | ||
233 | static Evas_Font_Set * | ||
234 | evas_load_fontconfig(Evas *evas, FcFontSet *set, int size, | ||
235 | Font_Rend_Flags wanted_rend) | ||
236 | { | ||
237 | Evas_Font_Set *font = NULL; | ||
238 | int i; | ||
239 | |||
240 | /* Do loading for all in family */ | ||
241 | for (i = 0; i < set->nfont; i++) | ||
242 | { | ||
243 | FcValue filename; | ||
244 | |||
245 | FcPatternGet(set->fonts[i], FC_FILE, 0, &filename); | ||
246 | |||
247 | if (font) | ||
248 | evas->engine.func->font_add(evas->engine.data.output, font, (char *)filename.u.s, size, wanted_rend); | ||
249 | else | ||
250 | font = evas->engine.func->font_load(evas->engine.data.output, (char *)filename.u.s, size, wanted_rend); | ||
251 | } | ||
252 | |||
253 | return font; | ||
254 | } | ||
255 | #endif | ||
256 | |||
257 | #ifdef HAVE_FONTCONFIG | ||
258 | /* In sync with Evas_Font_Style, Evas_Font_Weight and Evas_Font_Width */ | ||
259 | static int _fc_slant_map[] = | ||
260 | { | ||
261 | FC_SLANT_ROMAN, | ||
262 | FC_SLANT_OBLIQUE, | ||
263 | FC_SLANT_ITALIC | ||
264 | }; | ||
265 | |||
266 | static int _fc_weight_map[] = | ||
267 | { | ||
268 | FC_WEIGHT_NORMAL, | ||
269 | FC_WEIGHT_THIN, | ||
270 | FC_WEIGHT_ULTRALIGHT, | ||
271 | FC_WEIGHT_LIGHT, | ||
272 | FC_WEIGHT_BOOK, | ||
273 | FC_WEIGHT_MEDIUM, | ||
274 | FC_WEIGHT_SEMIBOLD, | ||
275 | FC_WEIGHT_BOLD, | ||
276 | FC_WEIGHT_ULTRABOLD, | ||
277 | FC_WEIGHT_BLACK, | ||
278 | FC_WEIGHT_EXTRABLACK | ||
279 | }; | ||
280 | |||
281 | # ifdef FC_WIDTH | ||
282 | static int _fc_width_map[] = | ||
283 | { | ||
284 | FC_WIDTH_NORMAL, | ||
285 | FC_WIDTH_ULTRACONDENSED, | ||
286 | FC_WIDTH_EXTRACONDENSED, | ||
287 | FC_WIDTH_CONDENSED, | ||
288 | FC_WIDTH_SEMICONDENSED, | ||
289 | FC_WIDTH_SEMIEXPANDED, | ||
290 | FC_WIDTH_EXPANDED, | ||
291 | FC_WIDTH_EXTRAEXPANDED, | ||
292 | FC_WIDTH_ULTRAEXPANDED | ||
293 | }; | ||
294 | # endif | ||
295 | |||
296 | #endif | ||
297 | |||
298 | struct _Style_Map | ||
299 | { | ||
300 | const char *name; | ||
301 | int type; | ||
302 | }; | ||
303 | typedef struct _Style_Map Style_Map; | ||
304 | |||
305 | static Style_Map _style_width_map[] = | ||
306 | { | ||
307 | {"normal", EVAS_FONT_WIDTH_NORMAL}, | ||
308 | {"ultracondensed", EVAS_FONT_WIDTH_ULTRACONDENSED}, | ||
309 | {"extracondensed", EVAS_FONT_WIDTH_EXTRACONDENSED}, | ||
310 | {"condensed", EVAS_FONT_WIDTH_CONDENSED}, | ||
311 | {"semicondensed", EVAS_FONT_WIDTH_SEMICONDENSED}, | ||
312 | {"semiexpanded", EVAS_FONT_WIDTH_SEMIEXPANDED}, | ||
313 | {"expanded", EVAS_FONT_WIDTH_EXPANDED}, | ||
314 | {"extraexpanded", EVAS_FONT_WIDTH_EXTRAEXPANDED}, | ||
315 | {"ultraexpanded", EVAS_FONT_WIDTH_ULTRAEXPANDED}, | ||
316 | }; | ||
317 | |||
318 | static Style_Map _style_weight_map[] = | ||
319 | { | ||
320 | {"normal", EVAS_FONT_WEIGHT_NORMAL}, | ||
321 | {"thin", EVAS_FONT_WEIGHT_THIN}, | ||
322 | {"ultralight", EVAS_FONT_WEIGHT_ULTRALIGHT}, | ||
323 | {"light", EVAS_FONT_WEIGHT_LIGHT}, | ||
324 | {"book", EVAS_FONT_WEIGHT_BOOK}, | ||
325 | {"medium", EVAS_FONT_WEIGHT_MEDIUM}, | ||
326 | {"semibold", EVAS_FONT_WEIGHT_SEMIBOLD}, | ||
327 | {"bold", EVAS_FONT_WEIGHT_BOLD}, | ||
328 | {"ultrabold", EVAS_FONT_WEIGHT_ULTRABOLD}, | ||
329 | {"black", EVAS_FONT_WEIGHT_BLACK}, | ||
330 | {"extrablack", EVAS_FONT_WEIGHT_EXTRABLACK} | ||
331 | }; | ||
332 | |||
333 | static Style_Map _style_slant_map[] = | ||
334 | { | ||
335 | {"normal", EVAS_FONT_SLANT_NORMAL}, | ||
336 | {"oblique", EVAS_FONT_SLANT_OBLIQUE}, | ||
337 | {"italic", EVAS_FONT_SLANT_ITALIC} | ||
338 | }; | ||
339 | |||
340 | #define _STYLE_MAP_LEN(x) (sizeof(x) / sizeof(*(x))) | ||
341 | /** | ||
342 | * @internal | ||
343 | * Find a certain attribute from the map in the style. | ||
344 | * @return the index of the found one. | ||
345 | */ | ||
346 | static int | ||
347 | _evas_font_style_find_internal(const char *style, const char *style_end, | ||
348 | Style_Map _map[], size_t map_len) | ||
349 | { | ||
350 | size_t i; | ||
351 | while (style < style_end) | ||
352 | { | ||
353 | for (i = 0 ; i < map_len ; i++) | ||
354 | { | ||
355 | size_t len; | ||
356 | const char *cur = _map[i].name; | ||
357 | len = strlen(cur); | ||
358 | if (!strncasecmp(style, cur, len) && | ||
359 | (!cur[len] || (cur[len] == ' '))) | ||
360 | { | ||
361 | return _map[i].type; | ||
362 | } | ||
363 | } | ||
364 | style = strchr(style, ' '); | ||
365 | if (!style) | ||
366 | break; | ||
367 | |||
368 | while (*style && (*style == ' ')) | ||
369 | style++; | ||
370 | } | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | int | ||
375 | evas_font_style_find(const char *start, const char *end, | ||
376 | Evas_Font_Style style) | ||
377 | { | ||
378 | #define _RET_STYLE(x) \ | ||
379 | return _evas_font_style_find_internal(start, end, \ | ||
380 | _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map)); | ||
381 | switch (style) | ||
382 | { | ||
383 | case EVAS_FONT_STYLE_SLANT: | ||
384 | _RET_STYLE(slant); | ||
385 | case EVAS_FONT_STYLE_WEIGHT: | ||
386 | _RET_STYLE(weight); | ||
387 | case EVAS_FONT_STYLE_WIDTH: | ||
388 | _RET_STYLE(width); | ||
389 | default: | ||
390 | return 0; | ||
391 | } | ||
392 | #undef _RET_STYLE | ||
393 | } | ||
394 | |||
395 | void | ||
396 | evas_font_desc_unref(Evas_Font_Description *fdesc) | ||
397 | { | ||
398 | if (--(fdesc->ref) == 0) | ||
399 | { | ||
400 | eina_stringshare_del(fdesc->name); | ||
401 | eina_stringshare_del(fdesc->fallbacks); | ||
402 | eina_stringshare_del(fdesc->lang); | ||
403 | free(fdesc); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | Evas_Font_Description * | ||
408 | evas_font_desc_ref(Evas_Font_Description *fdesc) | ||
409 | { | ||
410 | fdesc->ref++; | ||
411 | return fdesc; | ||
412 | } | ||
413 | |||
414 | Evas_Font_Description * | ||
415 | evas_font_desc_new(void) | ||
416 | { | ||
417 | Evas_Font_Description *fdesc; | ||
418 | fdesc = calloc(1, sizeof(*fdesc)); | ||
419 | fdesc->ref = 1; | ||
420 | fdesc->is_new = EINA_TRUE; | ||
421 | |||
422 | return fdesc; | ||
423 | } | ||
424 | |||
425 | Evas_Font_Description * | ||
426 | evas_font_desc_dup(const Evas_Font_Description *fdesc) | ||
427 | { | ||
428 | Evas_Font_Description *new; | ||
429 | new = evas_font_desc_new(); | ||
430 | memcpy(new, fdesc, sizeof(*new)); | ||
431 | new->ref = 1; | ||
432 | new->is_new = EINA_TRUE; | ||
433 | new->name = eina_stringshare_ref(new->name); | ||
434 | |||
435 | return new; | ||
436 | } | ||
437 | |||
438 | int | ||
439 | evas_font_desc_cmp(const Evas_Font_Description *a, | ||
440 | const Evas_Font_Description *b) | ||
441 | { | ||
442 | /* FIXME: Do actual comparison, i.e less than and bigger than. */ | ||
443 | return !((a->name == b->name) && (a->weight == b->weight) && | ||
444 | (a->slant == b->slant) && (a->width == b->width) && | ||
445 | (a->lang == b->lang)); | ||
446 | } | ||
447 | |||
448 | void | ||
449 | evas_font_name_parse(Evas_Font_Description *fdesc, const char *name) | ||
450 | { | ||
451 | const char *end; | ||
452 | |||
453 | end = strchr(name, ':'); | ||
454 | if (!end) | ||
455 | eina_stringshare_replace(&(fdesc->name), name); | ||
456 | else | ||
457 | eina_stringshare_replace_length(&(fdesc->name), name, end - name); | ||
458 | |||
459 | while (end) | ||
460 | { | ||
461 | const char *tend; | ||
462 | name = end; | ||
463 | end = strchr(end + 1, ':'); | ||
464 | if (!end) | ||
465 | tend = name + strlen(name); | ||
466 | else | ||
467 | tend = end; | ||
468 | |||
469 | if (!strncmp(name, ":style=", 7)) | ||
470 | { | ||
471 | #define _SET_STYLE(x) \ | ||
472 | fdesc->x = _evas_font_style_find_internal(name + 7, tend, \ | ||
473 | _style_##x##_map, _STYLE_MAP_LEN(_style_##x##_map)); | ||
474 | _SET_STYLE(slant); | ||
475 | _SET_STYLE(weight); | ||
476 | _SET_STYLE(width); | ||
477 | #undef _SET_STYLE | ||
478 | } | ||
479 | else if (!strncmp(name, ":lang=", 6)) | ||
480 | { | ||
481 | const char *tmp = name + 6; | ||
482 | eina_stringshare_replace_length(&(fdesc->lang), tmp, tend - tmp); | ||
483 | } | ||
484 | } | ||
485 | } | ||
486 | |||
487 | void * | ||
488 | evas_font_load(Evas *evas, Evas_Font_Description *fdesc, const char *source, Evas_Font_Size size) | ||
489 | { | ||
490 | #ifdef HAVE_FONTCONFIG | ||
491 | FcPattern *p_nm = NULL; | ||
492 | FcFontSet *set = NULL; | ||
493 | #endif | ||
494 | |||
495 | Evas_Font_Set *font = NULL; | ||
496 | Eina_List *fonts, *l; | ||
497 | Fndat *fd; | ||
498 | char *nm; | ||
499 | Font_Rend_Flags wanted_rend = 0; | ||
500 | |||
501 | if (!fdesc) return NULL; | ||
502 | fdesc->is_new = EINA_FALSE; | ||
503 | |||
504 | if (fdesc->slant != EVAS_FONT_SLANT_NORMAL) | ||
505 | wanted_rend |= FONT_REND_SLANT; | ||
506 | if (fdesc->weight == EVAS_FONT_WEIGHT_BOLD) | ||
507 | wanted_rend |= FONT_REND_WEIGHT; | ||
508 | |||
509 | evas_font_init(); | ||
510 | |||
511 | EINA_LIST_FOREACH(fonts_cache, l, fd) | ||
512 | { | ||
513 | if (!evas_font_desc_cmp(fdesc, fd->fdesc)) | ||
514 | { | ||
515 | if (((!source) && (!fd->source)) || | ||
516 | ((source) && (fd->source) && (!strcmp(source, fd->source)))) | ||
517 | { | ||
518 | if ((size == fd->size) && | ||
519 | (wanted_rend == fd->wanted_rend)) | ||
520 | { | ||
521 | fonts_cache = eina_list_promote_list(fonts_cache, l); | ||
522 | fd->ref++; | ||
523 | return fd->font; | ||
524 | } | ||
525 | #ifdef HAVE_FONTCONFIG | ||
526 | else if (fd->set && fd->p_nm) | ||
527 | { | ||
528 | font = evas_load_fontconfig(evas, fd->set, size, | ||
529 | wanted_rend); | ||
530 | goto on_find; | ||
531 | } | ||
532 | #endif | ||
533 | } | ||
534 | } | ||
535 | } | ||
536 | |||
537 | EINA_LIST_FOREACH(fonts_zero, l, fd) | ||
538 | { | ||
539 | if (!evas_font_desc_cmp(fdesc, fd->fdesc)) | ||
540 | { | ||
541 | if (((!source) && (!fd->source)) || | ||
542 | ((source) && (fd->source) && (!strcmp(source, fd->source)))) | ||
543 | { | ||
544 | if ((size == fd->size) && | ||
545 | (wanted_rend == fd->wanted_rend)) | ||
546 | { | ||
547 | fonts_zero = eina_list_remove_list(fonts_zero, l); | ||
548 | fonts_cache = eina_list_prepend(fonts_cache, fd); | ||
549 | fd->ref++; | ||
550 | return fd->font; | ||
551 | } | ||
552 | #ifdef HAVE_FONTCONFIG | ||
553 | else if (fd->set && fd->p_nm) | ||
554 | { | ||
555 | font = evas_load_fontconfig(evas, fd->set, size, | ||
556 | wanted_rend); | ||
557 | goto on_find; | ||
558 | } | ||
559 | #endif | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | |||
564 | fonts = evas_font_set_get(fdesc->name); | ||
565 | EINA_LIST_FOREACH(fonts, l, nm) /* Load each font in append */ | ||
566 | { | ||
567 | if (l == fonts || !font) /* First iteration OR no font */ | ||
568 | { | ||
569 | #ifdef BUILD_FONT_LOADER_EET | ||
570 | if (source) /* Load Font from "eet" source */ | ||
571 | { | ||
572 | Eet_File *ef; | ||
573 | char *fake_name; | ||
574 | |||
575 | fake_name = evas_file_path_join(source, nm); | ||
576 | if (fake_name) | ||
577 | { | ||
578 | font = evas->engine.func->font_load(evas->engine.data.output, fake_name, size, wanted_rend); | ||
579 | if (!font) /* Load from fake name failed, probably not cached */ | ||
580 | { | ||
581 | /* read original!!! */ | ||
582 | ef = eet_open(source, EET_FILE_MODE_READ); | ||
583 | if (ef) | ||
584 | { | ||
585 | void *fdata; | ||
586 | int fsize = 0; | ||
587 | |||
588 | fdata = eet_read(ef, nm, &fsize); | ||
589 | if ((fdata) && (fsize > 0)) | ||
590 | { | ||
591 | font = evas->engine.func->font_memory_load(evas->engine.data.output, fake_name, size, fdata, fsize, wanted_rend); | ||
592 | free(fdata); | ||
593 | } | ||
594 | eet_close(ef); | ||
595 | } | ||
596 | } | ||
597 | free(fake_name); | ||
598 | } | ||
599 | } | ||
600 | if (!font) /* Source load failed */ | ||
601 | { | ||
602 | #endif | ||
603 | if (evas_file_path_is_full_path((char *)nm)) /* Try filename */ | ||
604 | font = evas->engine.func->font_load(evas->engine.data.output, (char *)nm, size, wanted_rend); | ||
605 | else /* search font path */ | ||
606 | { | ||
607 | Eina_List *ll; | ||
608 | char *dir; | ||
609 | |||
610 | EINA_LIST_FOREACH(evas->font_path, ll, dir) | ||
611 | { | ||
612 | const char *f_file; | ||
613 | |||
614 | f_file = evas_font_dir_cache_find(dir, (char *)nm); | ||
615 | if (f_file) | ||
616 | { | ||
617 | font = evas->engine.func->font_load(evas->engine.data.output, f_file, size, wanted_rend); | ||
618 | if (font) break; | ||
619 | } | ||
620 | } | ||
621 | } | ||
622 | #ifdef BUILD_FONT_LOADER_EET | ||
623 | } | ||
624 | #endif | ||
625 | } | ||
626 | else /* Base font loaded, append others */ | ||
627 | { | ||
628 | #ifdef BUILD_FONT_LOADER_EET | ||
629 | void *ok = NULL; | ||
630 | |||
631 | if (source) | ||
632 | { | ||
633 | Eet_File *ef; | ||
634 | char *fake_name; | ||
635 | |||
636 | fake_name = evas_file_path_join(source, nm); | ||
637 | if (fake_name) | ||
638 | { | ||
639 | /* FIXME: make an engine func */ | ||
640 | if (!evas->engine.func->font_add(evas->engine.data.output, font, fake_name, size, wanted_rend)) | ||
641 | { | ||
642 | /* read original!!! */ | ||
643 | ef = eet_open(source, EET_FILE_MODE_READ); | ||
644 | if (ef) | ||
645 | { | ||
646 | void *fdata; | ||
647 | int fsize = 0; | ||
648 | |||
649 | fdata = eet_read(ef, nm, &fsize); | ||
650 | if ((fdata) && (fsize > 0)) | ||
651 | { | ||
652 | ok = evas->engine.func->font_memory_add(evas->engine.data.output, font, fake_name, size, fdata, fsize, wanted_rend); | ||
653 | free(fdata); | ||
654 | } | ||
655 | eet_close(ef); | ||
656 | } | ||
657 | } | ||
658 | else | ||
659 | ok = (void *)1; | ||
660 | free(fake_name); | ||
661 | } | ||
662 | } | ||
663 | if (!ok) | ||
664 | { | ||
665 | #endif | ||
666 | if (evas_file_path_is_full_path((char *)nm)) | ||
667 | evas->engine.func->font_add(evas->engine.data.output, font, (char *)nm, size, wanted_rend); | ||
668 | else | ||
669 | { | ||
670 | Eina_List *ll; | ||
671 | char *dir; | ||
672 | |||
673 | EINA_LIST_FOREACH(evas->font_path, ll, dir) | ||
674 | { | ||
675 | const char *f_file; | ||
676 | |||
677 | f_file = evas_font_dir_cache_find(dir, (char *)nm); | ||
678 | if (f_file) | ||
679 | { | ||
680 | if (evas->engine.func->font_add(evas->engine.data.output, font, f_file, size, wanted_rend)) | ||
681 | break; | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | #ifdef BUILD_FONT_LOADER_EET | ||
686 | } | ||
687 | #endif | ||
688 | } | ||
689 | eina_stringshare_del(nm); | ||
690 | } | ||
691 | fonts = eina_list_free(fonts); | ||
692 | |||
693 | #ifdef HAVE_FONTCONFIG | ||
694 | if (!font) /* Search using fontconfig */ | ||
695 | { | ||
696 | FcResult res; | ||
697 | |||
698 | p_nm = FcPatternBuild (NULL, | ||
699 | FC_WEIGHT, FcTypeInteger, _fc_weight_map[fdesc->weight], | ||
700 | FC_SLANT, FcTypeInteger, _fc_slant_map[fdesc->slant], | ||
701 | #ifdef FC_WIDTH | ||
702 | FC_WIDTH, FcTypeInteger, _fc_width_map[fdesc->width], | ||
703 | #endif | ||
704 | NULL); | ||
705 | FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) fdesc->name); | ||
706 | |||
707 | /* Handle font fallbacks */ | ||
708 | if (fdesc->fallbacks) | ||
709 | { | ||
710 | while (1) | ||
711 | { | ||
712 | const char *start, *end; | ||
713 | start = fdesc->fallbacks; | ||
714 | end = strchr(start, ','); | ||
715 | if (end) | ||
716 | { | ||
717 | char *tmp = alloca((end - start) + 1); | ||
718 | strncpy(tmp, start, end - start); | ||
719 | tmp[end - start] = 0; | ||
720 | FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) tmp); | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | FcPatternAddString (p_nm, FC_FAMILY, (FcChar8*) start); | ||
725 | break; | ||
726 | } | ||
727 | } | ||
728 | } | ||
729 | |||
730 | if (fdesc->lang) | ||
731 | FcPatternAddString (p_nm, FC_LANG, (FcChar8 *) fdesc->lang); | ||
732 | |||
733 | FcConfigSubstitute(NULL, p_nm, FcMatchPattern); | ||
734 | FcDefaultSubstitute(p_nm); | ||
735 | |||
736 | /* do matching */ | ||
737 | set = FcFontSort(NULL, p_nm, FcTrue, NULL, &res); | ||
738 | if (!set) | ||
739 | { | ||
740 | ERR("No fontconfig font matches '%s'. It was the last resource, no font found!", fdesc->name); | ||
741 | FcPatternDestroy(p_nm); | ||
742 | p_nm = NULL; | ||
743 | } | ||
744 | else | ||
745 | { | ||
746 | font = evas_load_fontconfig(evas, set, size, wanted_rend); | ||
747 | } | ||
748 | } | ||
749 | #endif | ||
750 | |||
751 | #ifdef HAVE_FONTCONFIG | ||
752 | on_find: | ||
753 | #endif | ||
754 | fd = calloc(1, sizeof(Fndat)); | ||
755 | if (fd) | ||
756 | { | ||
757 | fd->fdesc = evas_font_desc_ref(fdesc); | ||
758 | if (source) fd->source = eina_stringshare_add(source); | ||
759 | fd->font = font; | ||
760 | fd->wanted_rend = wanted_rend; | ||
761 | fd->size = size; | ||
762 | fd->ref = 1; | ||
763 | fonts_cache = eina_list_prepend(fonts_cache, fd); | ||
764 | #ifdef HAVE_FONTCONFIG | ||
765 | fd->set = set; | ||
766 | fd->p_nm = p_nm; | ||
767 | #endif | ||
768 | } | ||
769 | |||
770 | if (font) | ||
771 | evas->engine.func->font_hinting_set(evas->engine.data.output, font, | ||
772 | evas->hinting); | ||
773 | return font; | ||
774 | } | ||
775 | |||
776 | void | ||
777 | evas_font_load_hinting_set(Evas *evas, void *font, int hinting) | ||
778 | { | ||
779 | evas->engine.func->font_hinting_set(evas->engine.data.output, font, | ||
780 | hinting); | ||
781 | } | ||
782 | |||
783 | Eina_List * | ||
784 | evas_font_dir_available_list(const Evas *evas) | ||
785 | { | ||
786 | Eina_List *l; | ||
787 | Eina_List *ll; | ||
788 | Eina_List *available = NULL; | ||
789 | char *dir; | ||
790 | |||
791 | #ifdef HAVE_FONTCONFIG | ||
792 | /* Add font config fonts */ | ||
793 | FcPattern *p; | ||
794 | FcFontSet *set = NULL; | ||
795 | FcObjectSet *os; | ||
796 | int i; | ||
797 | |||
798 | evas_font_init(); | ||
799 | |||
800 | p = FcPatternCreate(); | ||
801 | os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, NULL); | ||
802 | |||
803 | if (p && os) set = FcFontList(NULL, p, os); | ||
804 | |||
805 | if (p) FcPatternDestroy(p); | ||
806 | if (os) FcObjectSetDestroy(os); | ||
807 | |||
808 | if (set) | ||
809 | { | ||
810 | for (i = 0; i < set->nfont; i++) | ||
811 | { | ||
812 | char *font; | ||
813 | |||
814 | font = (char *)FcNameUnparse(set->fonts[i]); | ||
815 | available = eina_list_append(available, eina_stringshare_add(font)); | ||
816 | free(font); | ||
817 | } | ||
818 | |||
819 | FcFontSetDestroy(set); | ||
820 | } | ||
821 | #endif | ||
822 | |||
823 | /* Add fonts in evas font_path*/ | ||
824 | if (!evas->font_path) | ||
825 | return available; | ||
826 | |||
827 | if (!font_dirs) font_dirs = eina_hash_string_superfast_new(NULL); | ||
828 | |||
829 | EINA_LIST_FOREACH(evas->font_path, l, dir) | ||
830 | { | ||
831 | Evas_Font_Dir *fd; | ||
832 | |||
833 | fd = eina_hash_find(font_dirs, dir); | ||
834 | fd = object_text_font_cache_dir_update(dir, fd); | ||
835 | if (fd && fd->aliases) | ||
836 | { | ||
837 | Evas_Font_Alias *fa; | ||
838 | |||
839 | EINA_LIST_FOREACH(fd->aliases, ll, fa) | ||
840 | available = eina_list_append(available, eina_stringshare_add((char *)fa->alias)); | ||
841 | } | ||
842 | } | ||
843 | |||
844 | return available; | ||
845 | } | ||
846 | |||
847 | void | ||
848 | evas_font_dir_available_list_free(Eina_List *available) | ||
849 | { | ||
850 | while (available) | ||
851 | { | ||
852 | eina_stringshare_del(available->data); | ||
853 | available = eina_list_remove(available, available->data); | ||
854 | } | ||
855 | } | ||
856 | |||
857 | /* private stuff */ | ||
858 | static Eina_Bool | ||
859 | font_cache_dir_free(const Eina_Hash *hash __UNUSED__, const void *key, void *data, void *fdata __UNUSED__) | ||
860 | { | ||
861 | object_text_font_cache_dir_del((char *) key, data); | ||
862 | return 1; | ||
863 | } | ||
864 | |||
865 | static Evas_Font_Dir * | ||
866 | object_text_font_cache_dir_update(char *dir, Evas_Font_Dir *fd) | ||
867 | { | ||
868 | DATA64 mt; | ||
869 | char *tmp; | ||
870 | |||
871 | if (fd) | ||
872 | { | ||
873 | mt = evas_file_modified_time(dir); | ||
874 | if (mt != fd->dir_mod_time) | ||
875 | { | ||
876 | object_text_font_cache_dir_del(dir, fd); | ||
877 | eina_hash_del(font_dirs, dir, fd); | ||
878 | } | ||
879 | else | ||
880 | { | ||
881 | tmp = evas_file_path_join(dir, "fonts.dir"); | ||
882 | if (tmp) | ||
883 | { | ||
884 | mt = evas_file_modified_time(tmp); | ||
885 | free(tmp); | ||
886 | if (mt != fd->fonts_dir_mod_time) | ||
887 | { | ||
888 | object_text_font_cache_dir_del(dir, fd); | ||
889 | eina_hash_del(font_dirs, dir, fd); | ||
890 | } | ||
891 | else | ||
892 | { | ||
893 | tmp = evas_file_path_join(dir, "fonts.alias"); | ||
894 | if (tmp) | ||
895 | { | ||
896 | mt = evas_file_modified_time(tmp); | ||
897 | free(tmp); | ||
898 | } | ||
899 | if (mt != fd->fonts_alias_mod_time) | ||
900 | { | ||
901 | object_text_font_cache_dir_del(dir, fd); | ||
902 | eina_hash_del(font_dirs, dir, fd); | ||
903 | } | ||
904 | else | ||
905 | return fd; | ||
906 | } | ||
907 | } | ||
908 | } | ||
909 | } | ||
910 | return object_text_font_cache_dir_add(dir); | ||
911 | } | ||
912 | |||
913 | static Evas_Font * | ||
914 | object_text_font_cache_font_find_x(Evas_Font_Dir *fd, char *font) | ||
915 | { | ||
916 | Eina_List *l; | ||
917 | char font_prop[14][256]; | ||
918 | int num; | ||
919 | Evas_Font *fn; | ||
920 | |||
921 | num = evas_object_text_font_string_parse(font, font_prop); | ||
922 | if (num != 14) return NULL; | ||
923 | EINA_LIST_FOREACH(fd->fonts, l, fn) | ||
924 | { | ||
925 | if (fn->type == 1) | ||
926 | { | ||
927 | int i; | ||
928 | int match = 0; | ||
929 | |||
930 | for (i = 0; i < 14; i++) | ||
931 | { | ||
932 | if ((font_prop[i][0] == '*') && (font_prop[i][1] == 0)) | ||
933 | match++; | ||
934 | else | ||
935 | { | ||
936 | if (!strcasecmp(font_prop[i], fn->x.prop[i])) match++; | ||
937 | else break; | ||
938 | } | ||
939 | } | ||
940 | if (match == 14) return fn; | ||
941 | } | ||
942 | } | ||
943 | return NULL; | ||
944 | } | ||
945 | |||
946 | static Evas_Font * | ||
947 | object_text_font_cache_font_find_file(Evas_Font_Dir *fd, char *font) | ||
948 | { | ||
949 | Eina_List *l; | ||
950 | Evas_Font *fn; | ||
951 | |||
952 | EINA_LIST_FOREACH(fd->fonts, l, fn) | ||
953 | { | ||
954 | if (fn->type == 0) | ||
955 | { | ||
956 | if (!strcasecmp(font, fn->simple.name)) return fn; | ||
957 | } | ||
958 | } | ||
959 | return NULL; | ||
960 | } | ||
961 | |||
962 | static Evas_Font * | ||
963 | object_text_font_cache_font_find_alias(Evas_Font_Dir *fd, char *font) | ||
964 | { | ||
965 | Eina_List *l; | ||
966 | Evas_Font_Alias *fa; | ||
967 | |||
968 | EINA_LIST_FOREACH(fd->aliases, l, fa) | ||
969 | if (!strcasecmp(fa->alias, font)) return fa->fn; | ||
970 | return NULL; | ||
971 | } | ||
972 | |||
973 | static Evas_Font * | ||
974 | object_text_font_cache_font_find(Evas_Font_Dir *fd, char *font) | ||
975 | { | ||
976 | Evas_Font *fn; | ||
977 | |||
978 | fn = eina_hash_find(fd->lookup, font); | ||
979 | if (fn) return fn; | ||
980 | fn = object_text_font_cache_font_find_alias(fd, font); | ||
981 | if (!fn) fn = object_text_font_cache_font_find_x(fd, font); | ||
982 | if (!fn) fn = object_text_font_cache_font_find_file(fd, font); | ||
983 | if (!fn) return NULL; | ||
984 | eina_hash_add(fd->lookup, font, fn); | ||
985 | return fn; | ||
986 | } | ||
987 | |||
988 | static Evas_Font_Dir * | ||
989 | object_text_font_cache_dir_add(char *dir) | ||
990 | { | ||
991 | Evas_Font_Dir *fd; | ||
992 | char *tmp, *tmp2; | ||
993 | Eina_List *fdir; | ||
994 | Evas_Font *fn; | ||
995 | |||
996 | fd = calloc(1, sizeof(Evas_Font_Dir)); | ||
997 | if (!fd) return NULL; | ||
998 | fd->lookup = eina_hash_string_superfast_new(NULL); | ||
999 | |||
1000 | eina_hash_add(font_dirs, dir, fd); | ||
1001 | |||
1002 | /* READ fonts.alias, fonts.dir and directory listing */ | ||
1003 | |||
1004 | /* fonts.dir */ | ||
1005 | tmp = evas_file_path_join(dir, "fonts.dir"); | ||
1006 | if (tmp) | ||
1007 | { | ||
1008 | FILE *f; | ||
1009 | |||
1010 | f = fopen(tmp, "rb"); | ||
1011 | if (f) | ||
1012 | { | ||
1013 | int num; | ||
1014 | char fname[4096], fdef[4096]; | ||
1015 | |||
1016 | if (fscanf(f, "%i\n", &num) != 1) goto cant_read; | ||
1017 | /* read font lines */ | ||
1018 | while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2) | ||
1019 | { | ||
1020 | char font_prop[14][256]; | ||
1021 | int i; | ||
1022 | |||
1023 | /* skip comments */ | ||
1024 | if ((fdef[0] == '!') || (fdef[0] == '#')) continue; | ||
1025 | /* parse font def */ | ||
1026 | num = evas_object_text_font_string_parse((char *)fdef, font_prop); | ||
1027 | if (num == 14) | ||
1028 | { | ||
1029 | fn = calloc(1, sizeof(Evas_Font)); | ||
1030 | if (fn) | ||
1031 | { | ||
1032 | fn->type = 1; | ||
1033 | for (i = 0; i < 14; i++) | ||
1034 | fn->x.prop[i] = eina_stringshare_add(font_prop[i]); | ||
1035 | tmp2 = evas_file_path_join(dir, fname); | ||
1036 | if (tmp2) | ||
1037 | { | ||
1038 | fn->path = eina_stringshare_add(tmp2); | ||
1039 | free(tmp2); | ||
1040 | } | ||
1041 | fd->fonts = eina_list_append(fd->fonts, fn); | ||
1042 | } | ||
1043 | } | ||
1044 | } | ||
1045 | cant_read: ; | ||
1046 | fclose(f); | ||
1047 | } | ||
1048 | free(tmp); | ||
1049 | } | ||
1050 | |||
1051 | /* directoy listing */ | ||
1052 | fdir = evas_file_path_list(dir, "*.ttf", 0); | ||
1053 | while (fdir) | ||
1054 | { | ||
1055 | tmp = evas_file_path_join(dir, fdir->data); | ||
1056 | if (tmp) | ||
1057 | { | ||
1058 | fn = calloc(1, sizeof(Evas_Font)); | ||
1059 | if (fn) | ||
1060 | { | ||
1061 | char *p; | ||
1062 | |||
1063 | fn->type = 0; | ||
1064 | tmp2 = alloca(strlen(fdir->data) + 1); | ||
1065 | strcpy(tmp2, fdir->data); | ||
1066 | p = strrchr(tmp2, '.'); | ||
1067 | if (p) *p = 0; | ||
1068 | fn->simple.name = eina_stringshare_add(tmp2); | ||
1069 | tmp2 = evas_file_path_join(dir, fdir->data); | ||
1070 | if (tmp2) | ||
1071 | { | ||
1072 | fn->path = eina_stringshare_add(tmp2); | ||
1073 | free(tmp2); | ||
1074 | } | ||
1075 | fd->fonts = eina_list_append(fd->fonts, fn); | ||
1076 | } | ||
1077 | free(tmp); | ||
1078 | } | ||
1079 | free(fdir->data); | ||
1080 | fdir = eina_list_remove(fdir, fdir->data); | ||
1081 | } | ||
1082 | |||
1083 | /* fonts.alias */ | ||
1084 | tmp = evas_file_path_join(dir, "fonts.alias"); | ||
1085 | if (tmp) | ||
1086 | { | ||
1087 | FILE *f; | ||
1088 | |||
1089 | f = fopen(tmp, "rb"); | ||
1090 | if (f) | ||
1091 | { | ||
1092 | char fname[4096], fdef[4096]; | ||
1093 | |||
1094 | /* read font alias lines */ | ||
1095 | while (fscanf(f, "%4090s %[^\n]\n", fname, fdef) == 2) | ||
1096 | { | ||
1097 | Evas_Font_Alias *fa; | ||
1098 | |||
1099 | /* skip comments */ | ||
1100 | if ((fname[0] == '!') || (fname[0] == '#')) continue; | ||
1101 | fa = calloc(1, sizeof(Evas_Font_Alias)); | ||
1102 | if (fa) | ||
1103 | { | ||
1104 | fa->alias = eina_stringshare_add(fname); | ||
1105 | fa->fn = object_text_font_cache_font_find_x(fd, fdef); | ||
1106 | if ((!fa->alias) || (!fa->fn)) | ||
1107 | { | ||
1108 | if (fa->alias) eina_stringshare_del(fa->alias); | ||
1109 | free(fa); | ||
1110 | } | ||
1111 | else | ||
1112 | fd->aliases = eina_list_append(fd->aliases, fa); | ||
1113 | } | ||
1114 | } | ||
1115 | fclose(f); | ||
1116 | } | ||
1117 | free(tmp); | ||
1118 | } | ||
1119 | |||
1120 | fd->dir_mod_time = evas_file_modified_time(dir); | ||
1121 | tmp = evas_file_path_join(dir, "fonts.dir"); | ||
1122 | if (tmp) | ||
1123 | { | ||
1124 | fd->fonts_dir_mod_time = evas_file_modified_time(tmp); | ||
1125 | free(tmp); | ||
1126 | } | ||
1127 | tmp = evas_file_path_join(dir, "fonts.alias"); | ||
1128 | if (tmp) | ||
1129 | { | ||
1130 | fd->fonts_alias_mod_time = evas_file_modified_time(tmp); | ||
1131 | free(tmp); | ||
1132 | } | ||
1133 | |||
1134 | return fd; | ||
1135 | } | ||
1136 | |||
1137 | static void | ||
1138 | object_text_font_cache_dir_del(char *dir __UNUSED__, Evas_Font_Dir *fd) | ||
1139 | { | ||
1140 | if (fd->lookup) eina_hash_free(fd->lookup); | ||
1141 | while (fd->fonts) | ||
1142 | { | ||
1143 | Evas_Font *fn; | ||
1144 | int i; | ||
1145 | |||
1146 | fn = fd->fonts->data; | ||
1147 | fd->fonts = eina_list_remove(fd->fonts, fn); | ||
1148 | for (i = 0; i < 14; i++) | ||
1149 | { | ||
1150 | if (fn->x.prop[i]) eina_stringshare_del(fn->x.prop[i]); | ||
1151 | } | ||
1152 | if (fn->simple.name) eina_stringshare_del(fn->simple.name); | ||
1153 | if (fn->path) eina_stringshare_del(fn->path); | ||
1154 | free(fn); | ||
1155 | } | ||
1156 | while (fd->aliases) | ||
1157 | { | ||
1158 | Evas_Font_Alias *fa; | ||
1159 | |||
1160 | fa = fd->aliases->data; | ||
1161 | fd->aliases = eina_list_remove(fd->aliases, fa); | ||
1162 | if (fa->alias) eina_stringshare_del(fa->alias); | ||
1163 | free(fa); | ||
1164 | } | ||
1165 | free(fd); | ||
1166 | } | ||
1167 | |||
1168 | static int | ||
1169 | evas_object_text_font_string_parse(char *buffer, char dest[14][256]) | ||
1170 | { | ||
1171 | char *p; | ||
1172 | int n, m, i; | ||
1173 | |||
1174 | n = 0; | ||
1175 | m = 0; | ||
1176 | p = buffer; | ||
1177 | if (p[0] != '-') return 0; | ||
1178 | i = 1; | ||
1179 | while (p[i]) | ||
1180 | { | ||
1181 | dest[n][m] = p[i]; | ||
1182 | if ((p[i] == '-') || (m == 255)) | ||
1183 | { | ||
1184 | dest[n][m] = 0; | ||
1185 | n++; | ||
1186 | m = -1; | ||
1187 | } | ||
1188 | i++; | ||
1189 | m++; | ||
1190 | if (n == 14) return n; | ||
1191 | } | ||
1192 | dest[n][m] = 0; | ||
1193 | n++; | ||
1194 | return n; | ||
1195 | } | ||
1196 | |||
1197 | EAPI void | ||
1198 | evas_font_path_clear(Evas *e) | ||
1199 | { | ||
1200 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1201 | return; | ||
1202 | MAGIC_CHECK_END(); | ||
1203 | while (e->font_path) | ||
1204 | { | ||
1205 | eina_stringshare_del(e->font_path->data); | ||
1206 | e->font_path = eina_list_remove(e->font_path, e->font_path->data); | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | EAPI void | ||
1211 | evas_font_path_append(Evas *e, const char *path) | ||
1212 | { | ||
1213 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1214 | return; | ||
1215 | MAGIC_CHECK_END(); | ||
1216 | |||
1217 | if (!path) return; | ||
1218 | e->font_path = eina_list_append(e->font_path, eina_stringshare_add(path)); | ||
1219 | } | ||
1220 | |||
1221 | EAPI void | ||
1222 | evas_font_path_prepend(Evas *e, const char *path) | ||
1223 | { | ||
1224 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1225 | return; | ||
1226 | MAGIC_CHECK_END(); | ||
1227 | |||
1228 | if (!path) return; | ||
1229 | e->font_path = eina_list_prepend(e->font_path, eina_stringshare_add(path)); | ||
1230 | } | ||
1231 | |||
1232 | EAPI const Eina_List * | ||
1233 | evas_font_path_list(const Evas *e) | ||
1234 | { | ||
1235 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1236 | return NULL; | ||
1237 | MAGIC_CHECK_END(); | ||
1238 | return e->font_path; | ||
1239 | } | ||
1240 | |||
1241 | static void | ||
1242 | evas_font_object_rehint(Evas_Object *obj) | ||
1243 | { | ||
1244 | if (obj->smart.smart) | ||
1245 | { | ||
1246 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj) | ||
1247 | evas_font_object_rehint(obj); | ||
1248 | } | ||
1249 | else | ||
1250 | { | ||
1251 | if (!strcmp(obj->type, "text")) | ||
1252 | _evas_object_text_rehint(obj); | ||
1253 | if (!strcmp(obj->type, "textblock")) | ||
1254 | _evas_object_textblock_rehint(obj); | ||
1255 | } | ||
1256 | } | ||
1257 | |||
1258 | EAPI void | ||
1259 | evas_font_hinting_set(Evas *e, Evas_Font_Hinting_Flags hinting) | ||
1260 | { | ||
1261 | Evas_Layer *lay; | ||
1262 | |||
1263 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1264 | return; | ||
1265 | MAGIC_CHECK_END(); | ||
1266 | if (e->hinting == hinting) return; | ||
1267 | e->hinting = hinting; | ||
1268 | |||
1269 | EINA_INLIST_FOREACH(e->layers, lay) | ||
1270 | { | ||
1271 | Evas_Object *obj; | ||
1272 | |||
1273 | EINA_INLIST_FOREACH(lay->objects, obj) | ||
1274 | evas_font_object_rehint(obj); | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | EAPI Evas_Font_Hinting_Flags | ||
1279 | evas_font_hinting_get(const Evas *e) | ||
1280 | { | ||
1281 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1282 | return EVAS_FONT_HINTING_BYTECODE; | ||
1283 | MAGIC_CHECK_END(); | ||
1284 | return e->hinting; | ||
1285 | } | ||
1286 | |||
1287 | EAPI Eina_Bool | ||
1288 | evas_font_hinting_can_hint(const Evas *e, Evas_Font_Hinting_Flags hinting) | ||
1289 | { | ||
1290 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1291 | return 0; | ||
1292 | MAGIC_CHECK_END(); | ||
1293 | if (e->engine.func->font_hinting_can_hint) | ||
1294 | return e->engine.func->font_hinting_can_hint(e->engine.data.output, | ||
1295 | hinting); | ||
1296 | return EINA_FALSE; | ||
1297 | } | ||
1298 | |||
1299 | EAPI void | ||
1300 | evas_font_cache_flush(Evas *e) | ||
1301 | { | ||
1302 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1303 | return; | ||
1304 | MAGIC_CHECK_END(); | ||
1305 | |||
1306 | e->engine.func->font_cache_flush(e->engine.data.output); | ||
1307 | } | ||
1308 | |||
1309 | EAPI void | ||
1310 | evas_font_cache_set(Evas *e, int size) | ||
1311 | { | ||
1312 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1313 | return; | ||
1314 | MAGIC_CHECK_END(); | ||
1315 | |||
1316 | if (size < 0) size = 0; | ||
1317 | e->engine.func->font_cache_set(e->engine.data.output, size); | ||
1318 | } | ||
1319 | |||
1320 | EAPI int | ||
1321 | evas_font_cache_get(const Evas *e) | ||
1322 | { | ||
1323 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1324 | return 0; | ||
1325 | MAGIC_CHECK_END(); | ||
1326 | |||
1327 | return e->engine.func->font_cache_get(e->engine.data.output); | ||
1328 | } | ||
1329 | |||
1330 | EAPI Eina_List * | ||
1331 | evas_font_available_list(const Evas *e) | ||
1332 | { | ||
1333 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1334 | return NULL; | ||
1335 | MAGIC_CHECK_END(); | ||
1336 | |||
1337 | return evas_font_dir_available_list(e); | ||
1338 | } | ||
1339 | |||
1340 | EAPI void | ||
1341 | evas_font_available_list_free(Evas *e, Eina_List *available) | ||
1342 | { | ||
1343 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1344 | return; | ||
1345 | MAGIC_CHECK_END(); | ||
1346 | |||
1347 | evas_font_dir_available_list_free(available); | ||
1348 | } | ||
1349 | |||
diff --git a/libraries/evas/src/lib/canvas/evas_gl.c b/libraries/evas/src/lib/canvas/evas_gl.c new file mode 100644 index 0000000..47bb583 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_gl.c | |||
@@ -0,0 +1,245 @@ | |||
1 | /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/ | ||
2 | #include "evas_common.h" | ||
3 | #include "evas_private.h" | ||
4 | #include "Evas_GL.h" | ||
5 | |||
6 | struct _Evas_GL | ||
7 | { | ||
8 | DATA32 magic; | ||
9 | Evas *evas; | ||
10 | |||
11 | Eina_List *contexts; | ||
12 | Eina_List *surfaces; | ||
13 | }; | ||
14 | |||
15 | struct _Evas_GL_Context | ||
16 | { | ||
17 | void *data; | ||
18 | }; | ||
19 | |||
20 | struct _Evas_GL_Surface | ||
21 | { | ||
22 | void *data; | ||
23 | }; | ||
24 | |||
25 | EAPI Evas_GL * | ||
26 | evas_gl_new(Evas *e) | ||
27 | { | ||
28 | Evas_GL *evas_gl; | ||
29 | |||
30 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
31 | return NULL; | ||
32 | MAGIC_CHECK_END(); | ||
33 | |||
34 | evas_gl = calloc(1, sizeof(Evas_GL)); | ||
35 | if (!evas_gl) return NULL; | ||
36 | |||
37 | evas_gl->magic = MAGIC_EVAS_GL; | ||
38 | evas_gl->evas = e; | ||
39 | |||
40 | return evas_gl; | ||
41 | } | ||
42 | |||
43 | EAPI void | ||
44 | evas_gl_free(Evas_GL *evas_gl) | ||
45 | { | ||
46 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
47 | return; | ||
48 | MAGIC_CHECK_END(); | ||
49 | |||
50 | |||
51 | // Delete undeleted surfaces | ||
52 | while (evas_gl->surfaces) | ||
53 | evas_gl_surface_destroy(evas_gl, evas_gl->surfaces->data); | ||
54 | |||
55 | // Delete undeleted contexts | ||
56 | while (evas_gl->contexts) | ||
57 | evas_gl_context_destroy(evas_gl, evas_gl->contexts->data); | ||
58 | |||
59 | evas_gl->magic = 0; | ||
60 | free(evas_gl); | ||
61 | } | ||
62 | |||
63 | EAPI Evas_GL_Surface * | ||
64 | evas_gl_surface_create(Evas_GL *evas_gl, Evas_GL_Config *config, int width, int height) | ||
65 | { | ||
66 | Evas_GL_Surface *surf; | ||
67 | |||
68 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
69 | return NULL; | ||
70 | MAGIC_CHECK_END(); | ||
71 | |||
72 | if (!config) | ||
73 | { | ||
74 | ERR("Invalid Config\n"); | ||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | surf = calloc(1, sizeof(Evas_GL_Surface)); | ||
79 | |||
80 | surf->data = evas_gl->evas->engine.func->gl_surface_create(evas_gl->evas->engine.data.output, config, width, height); | ||
81 | |||
82 | if (!surf->data) | ||
83 | { | ||
84 | ERR("Failed creating a surface from the engine\n"); | ||
85 | free(surf); | ||
86 | return NULL; | ||
87 | } | ||
88 | |||
89 | // Keep track of the surface creations | ||
90 | evas_gl->surfaces = eina_list_prepend(evas_gl->surfaces, surf); | ||
91 | |||
92 | return surf; | ||
93 | } | ||
94 | |||
95 | EAPI void | ||
96 | evas_gl_surface_destroy(Evas_GL *evas_gl, Evas_GL_Surface *surf) | ||
97 | { | ||
98 | // Magic | ||
99 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
100 | return; | ||
101 | MAGIC_CHECK_END(); | ||
102 | |||
103 | if (!surf) | ||
104 | { | ||
105 | ERR("Trying to destroy a NULL surface pointer!\n"); | ||
106 | return; | ||
107 | } | ||
108 | |||
109 | // Call Engine's Surface Destroy | ||
110 | evas_gl->evas->engine.func->gl_surface_destroy(evas_gl->evas->engine.data.output, surf->data); | ||
111 | |||
112 | // Remove it from the list | ||
113 | evas_gl->surfaces = eina_list_remove(evas_gl->surfaces, surf); | ||
114 | |||
115 | // Delete the object | ||
116 | free(surf); | ||
117 | surf = NULL; | ||
118 | } | ||
119 | |||
120 | EAPI Evas_GL_Context * | ||
121 | evas_gl_context_create(Evas_GL *evas_gl, Evas_GL_Context *share_ctx) | ||
122 | { | ||
123 | Evas_GL_Context *ctx; | ||
124 | |||
125 | // Magic | ||
126 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
127 | return NULL; | ||
128 | MAGIC_CHECK_END(); | ||
129 | |||
130 | // Allocate a context object | ||
131 | ctx = calloc(1, sizeof(Evas_GL_Context)); | ||
132 | if (!ctx) | ||
133 | { | ||
134 | ERR("Unable to create a Evas_GL_Context object\n"); | ||
135 | return NULL; | ||
136 | } | ||
137 | |||
138 | // Call engine->gl_create_context | ||
139 | if (share_ctx) | ||
140 | { | ||
141 | ctx->data = evas_gl->evas->engine.func->gl_context_create(evas_gl->evas->engine.data.output, share_ctx->data); | ||
142 | } | ||
143 | else | ||
144 | { | ||
145 | ctx->data = evas_gl->evas->engine.func->gl_context_create(evas_gl->evas->engine.data.output, NULL); | ||
146 | } | ||
147 | |||
148 | // Set a few variables | ||
149 | if (!ctx->data) | ||
150 | { | ||
151 | ERR("Failed creating a context from the engine\n"); | ||
152 | free(ctx); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | // Keep track of the context creations | ||
157 | evas_gl->contexts = eina_list_prepend(evas_gl->contexts, ctx); | ||
158 | |||
159 | return ctx; | ||
160 | |||
161 | } | ||
162 | |||
163 | EAPI void | ||
164 | evas_gl_context_destroy(Evas_GL *evas_gl, Evas_GL_Context *ctx) | ||
165 | { | ||
166 | |||
167 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
168 | return; | ||
169 | MAGIC_CHECK_END(); | ||
170 | |||
171 | if (!ctx) | ||
172 | { | ||
173 | ERR("Trying to destroy a NULL context pointer!\n"); | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | // Call Engine's destroy | ||
178 | evas_gl->evas->engine.func->gl_context_destroy(evas_gl->evas->engine.data.output, ctx->data); | ||
179 | |||
180 | // Remove it from the list | ||
181 | evas_gl->contexts = eina_list_remove(evas_gl->contexts, ctx); | ||
182 | |||
183 | // Delete the object | ||
184 | free(ctx); | ||
185 | ctx = NULL; | ||
186 | } | ||
187 | |||
188 | EAPI Eina_Bool | ||
189 | evas_gl_make_current(Evas_GL *evas_gl, Evas_GL_Surface *surf, Evas_GL_Context *ctx) | ||
190 | { | ||
191 | Eina_Bool ret; | ||
192 | |||
193 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
194 | return EINA_FALSE; | ||
195 | MAGIC_CHECK_END(); | ||
196 | |||
197 | if ((!surf) || (!ctx)) | ||
198 | ret = (Eina_Bool)evas_gl->evas->engine.func->gl_make_current(evas_gl->evas->engine.data.output, NULL, NULL); | ||
199 | else | ||
200 | ret = (Eina_Bool)evas_gl->evas->engine.func->gl_make_current(evas_gl->evas->engine.data.output, surf->data, ctx->data); | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | EAPI const char * | ||
206 | evas_gl_string_query(Evas_GL *evas_gl, int name) | ||
207 | { | ||
208 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
209 | return EINA_FALSE; | ||
210 | MAGIC_CHECK_END(); | ||
211 | |||
212 | return (const char *)evas_gl->evas->engine.func->gl_string_query(evas_gl->evas->engine.data.output, name); | ||
213 | } | ||
214 | |||
215 | EAPI Evas_GL_Func | ||
216 | evas_gl_proc_address_get(Evas_GL *evas_gl, const char *name) | ||
217 | { | ||
218 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
219 | return EINA_FALSE; | ||
220 | MAGIC_CHECK_END(); | ||
221 | |||
222 | return (Evas_GL_Func)evas_gl->evas->engine.func->gl_proc_address_get(evas_gl->evas->engine.data.output, name); | ||
223 | } | ||
224 | |||
225 | EAPI Eina_Bool | ||
226 | evas_gl_native_surface_get(Evas_GL *evas_gl, Evas_GL_Surface *surf, Evas_Native_Surface *ns) | ||
227 | { | ||
228 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
229 | return EINA_FALSE; | ||
230 | MAGIC_CHECK_END(); | ||
231 | |||
232 | return (Eina_Bool)evas_gl->evas->engine.func->gl_native_surface_get(evas_gl->evas->engine.data.output, surf->data, ns); | ||
233 | } | ||
234 | |||
235 | |||
236 | EAPI Evas_GL_API * | ||
237 | evas_gl_api_get(Evas_GL *evas_gl) | ||
238 | { | ||
239 | MAGIC_CHECK(evas_gl, Evas_GL, MAGIC_EVAS_GL); | ||
240 | return NULL; | ||
241 | MAGIC_CHECK_END(); | ||
242 | |||
243 | return (Evas_GL_API*)evas_gl->evas->engine.func->gl_api_get(evas_gl->evas->engine.data.output); | ||
244 | |||
245 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_key.c b/libraries/evas/src/lib/canvas/evas_key.c new file mode 100644 index 0000000..f74ef34 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_key.c | |||
@@ -0,0 +1,245 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* private calls */ | ||
5 | |||
6 | static int | ||
7 | evas_key_modifier_number(const Evas_Modifier *m, const char *keyname) | ||
8 | { | ||
9 | int i; | ||
10 | |||
11 | for (i = 0; i < m->mod.count; i++) | ||
12 | { | ||
13 | if (!strcmp(m->mod.list[i], keyname)) return i; | ||
14 | } | ||
15 | return -1; | ||
16 | } | ||
17 | |||
18 | static int | ||
19 | evas_key_lock_number(const Evas_Lock *l, const char *keyname) | ||
20 | { | ||
21 | int i; | ||
22 | |||
23 | for (i = 0; i < l->lock.count; i++) | ||
24 | { | ||
25 | if (!strcmp(l->lock.list[i], keyname)) return i; | ||
26 | } | ||
27 | return -1; | ||
28 | } | ||
29 | |||
30 | /* local calls */ | ||
31 | |||
32 | /* public calls */ | ||
33 | |||
34 | EAPI const Evas_Modifier * | ||
35 | evas_key_modifier_get(const Evas *e) | ||
36 | { | ||
37 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
38 | return NULL; | ||
39 | MAGIC_CHECK_END(); | ||
40 | return &(e->modifiers); | ||
41 | } | ||
42 | |||
43 | EAPI const Evas_Lock * | ||
44 | evas_key_lock_get(const Evas *e) | ||
45 | { | ||
46 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
47 | return NULL; | ||
48 | MAGIC_CHECK_END(); | ||
49 | return &(e->locks); | ||
50 | } | ||
51 | |||
52 | EAPI Eina_Bool | ||
53 | evas_key_modifier_is_set(const Evas_Modifier *m, const char *keyname) | ||
54 | { | ||
55 | Evas_Modifier_Mask num; | ||
56 | int n; | ||
57 | |||
58 | if (!m) return 0; | ||
59 | if (!keyname) return 0; | ||
60 | n = evas_key_modifier_number(m, keyname); | ||
61 | if (n < 0) return 0; | ||
62 | num = (Evas_Modifier_Mask)n; | ||
63 | num = 1 << num; | ||
64 | if (m->mask & num) return 1; | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | EAPI Eina_Bool | ||
69 | evas_key_lock_is_set(const Evas_Lock *l, const char *keyname) | ||
70 | { | ||
71 | Evas_Modifier_Mask num; | ||
72 | int n; | ||
73 | |||
74 | if (!l) return 0; | ||
75 | if (!keyname) return 0; | ||
76 | n = evas_key_lock_number(l, keyname); | ||
77 | if (n < 0) return 0; | ||
78 | num = (Evas_Modifier_Mask)n; | ||
79 | num = 1 << num; | ||
80 | if (l->mask & num) return 1; | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | EAPI void | ||
85 | evas_key_modifier_add(Evas *e, const char *keyname) | ||
86 | { | ||
87 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
88 | return; | ||
89 | MAGIC_CHECK_END(); | ||
90 | if (!keyname) return; | ||
91 | if (e->modifiers.mod.count >= 64) return; | ||
92 | evas_key_modifier_del(e, keyname); | ||
93 | e->modifiers.mod.count++; | ||
94 | e->modifiers.mod.list = realloc(e->modifiers.mod.list, e->modifiers.mod.count * sizeof(char *)); | ||
95 | e->modifiers.mod.list[e->modifiers.mod.count - 1] = strdup(keyname); | ||
96 | e->modifiers.mask = 0; | ||
97 | } | ||
98 | |||
99 | EAPI void | ||
100 | evas_key_modifier_del(Evas *e, const char *keyname) | ||
101 | { | ||
102 | int i; | ||
103 | |||
104 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
105 | return; | ||
106 | MAGIC_CHECK_END(); | ||
107 | if (!keyname) return; | ||
108 | for (i = 0; i < e->modifiers.mod.count; i++) | ||
109 | { | ||
110 | if (!strcmp(e->modifiers.mod.list[i], keyname)) | ||
111 | { | ||
112 | int j; | ||
113 | |||
114 | free(e->modifiers.mod.list[i]); | ||
115 | e->modifiers.mod.count--; | ||
116 | for (j = i; j < e->modifiers.mod.count; j++) | ||
117 | e->modifiers.mod.list[j] = e->modifiers.mod.list[j + 1]; | ||
118 | e->modifiers.mask = 0; | ||
119 | return; | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | EAPI void | ||
125 | evas_key_lock_add(Evas *e, const char *keyname) | ||
126 | { | ||
127 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
128 | return; | ||
129 | MAGIC_CHECK_END(); | ||
130 | if (!keyname) return; | ||
131 | if (e->locks.lock.count >= 64) return; | ||
132 | evas_key_lock_del(e, keyname); | ||
133 | e->locks.lock.count++; | ||
134 | e->locks.lock.list = realloc(e->locks.lock.list, e->locks.lock.count * sizeof(char *)); | ||
135 | e->locks.lock.list[e->locks.lock.count - 1] = strdup(keyname); | ||
136 | e->locks.mask = 0; | ||
137 | } | ||
138 | |||
139 | EAPI void | ||
140 | evas_key_lock_del(Evas *e, const char *keyname) | ||
141 | { | ||
142 | int i; | ||
143 | |||
144 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
145 | return; | ||
146 | MAGIC_CHECK_END(); | ||
147 | if (!keyname) return; | ||
148 | e->locks.mask = 0; | ||
149 | for (i = 0; i < e->locks.lock.count; i++) | ||
150 | { | ||
151 | if (!strcmp(e->locks.lock.list[i], keyname)) | ||
152 | { | ||
153 | int j; | ||
154 | |||
155 | free(e->locks.lock.list[i]); | ||
156 | e->locks.lock.count--; | ||
157 | for (j = i; j < e->locks.lock.count; j++) | ||
158 | e->locks.lock.list[j] = e->locks.lock.list[j + 1]; | ||
159 | e->locks.mask = 0; | ||
160 | return; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | EAPI void | ||
166 | evas_key_modifier_on(Evas *e, const char *keyname) | ||
167 | { | ||
168 | Evas_Modifier_Mask num; | ||
169 | int n; | ||
170 | |||
171 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
172 | return; | ||
173 | MAGIC_CHECK_END(); | ||
174 | n = (Evas_Modifier_Mask)evas_key_modifier_number(&(e->modifiers), keyname); | ||
175 | if (n < 0) return; | ||
176 | num = (Evas_Modifier_Mask)n; | ||
177 | num = 1 << num; | ||
178 | e->modifiers.mask |= num; | ||
179 | } | ||
180 | |||
181 | EAPI void | ||
182 | evas_key_modifier_off(Evas *e, const char *keyname) | ||
183 | { | ||
184 | Evas_Modifier_Mask num; | ||
185 | int n; | ||
186 | |||
187 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
188 | return; | ||
189 | MAGIC_CHECK_END(); | ||
190 | n = evas_key_modifier_number(&(e->modifiers), keyname); | ||
191 | if (n < 0) return; | ||
192 | num = (Evas_Modifier_Mask)n; | ||
193 | num = 1 << num; | ||
194 | e->modifiers.mask &= ~num; | ||
195 | } | ||
196 | |||
197 | EAPI void | ||
198 | evas_key_lock_on(Evas *e, const char *keyname) | ||
199 | { | ||
200 | Evas_Modifier_Mask num; | ||
201 | int n; | ||
202 | |||
203 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
204 | return; | ||
205 | MAGIC_CHECK_END(); | ||
206 | n = evas_key_lock_number(&(e->locks), keyname); | ||
207 | if (n < 0) return; | ||
208 | num = (Evas_Modifier_Mask)n; | ||
209 | num = 1 << num; | ||
210 | e->locks.mask |= num; | ||
211 | } | ||
212 | |||
213 | EAPI void | ||
214 | evas_key_lock_off(Evas *e, const char *keyname) | ||
215 | { | ||
216 | Evas_Modifier_Mask num; | ||
217 | int n; | ||
218 | |||
219 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
220 | return; | ||
221 | MAGIC_CHECK_END(); | ||
222 | n = evas_key_lock_number(&(e->locks), keyname); | ||
223 | if (n < 0) return; | ||
224 | num = (Evas_Modifier_Mask)n; | ||
225 | num = 1 << num; | ||
226 | e->locks.mask &= ~num; | ||
227 | } | ||
228 | |||
229 | /* errr need to add key grabbing/ungrabbing calls - missing modifier stuff. */ | ||
230 | |||
231 | EAPI Evas_Modifier_Mask | ||
232 | evas_key_modifier_mask_get(const Evas *e, const char *keyname) | ||
233 | { | ||
234 | Evas_Modifier_Mask num; | ||
235 | int n; | ||
236 | |||
237 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
238 | return 0; | ||
239 | MAGIC_CHECK_END(); | ||
240 | if (!keyname) return 0; | ||
241 | n = evas_key_modifier_number(&(e->modifiers), keyname); | ||
242 | if (n < 0) return 0; | ||
243 | num = (Evas_Modifier_Mask)n; | ||
244 | return 1 << num; | ||
245 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_key_grab.c b/libraries/evas/src/lib/canvas/evas_key_grab.c new file mode 100644 index 0000000..3fc2172 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_key_grab.c | |||
@@ -0,0 +1,179 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* private calls */ | ||
5 | |||
6 | /* FIXME: this is not optimal, but works. i should have a hash of keys per */ | ||
7 | /* Evas and then a linked lists of grabs for that key and what */ | ||
8 | /* modifiers/not_modifers they use */ | ||
9 | |||
10 | static Evas_Key_Grab *evas_key_grab_new (Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive); | ||
11 | static Evas_Key_Grab *evas_key_grab_find (Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive); | ||
12 | |||
13 | static Evas_Key_Grab * | ||
14 | evas_key_grab_new(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive) | ||
15 | { | ||
16 | /* MEM OK */ | ||
17 | Evas_Key_Grab *g; | ||
18 | |||
19 | g = evas_mem_calloc(sizeof(Evas_Key_Grab)); | ||
20 | if (!g) return NULL; | ||
21 | g->object = obj; | ||
22 | g->modifiers = modifiers; | ||
23 | g->not_modifiers = not_modifiers; | ||
24 | g->exclusive = exclusive; | ||
25 | g->keyname = strdup(keyname); | ||
26 | if (obj->layer->evas->walking_grabs) | ||
27 | g->just_added = EINA_TRUE; | ||
28 | if (!g->keyname) | ||
29 | { | ||
30 | if (!evas_mem_free(strlen(keyname) + 1)) | ||
31 | { | ||
32 | free(g); | ||
33 | return NULL; | ||
34 | } | ||
35 | g->keyname = strdup(keyname); | ||
36 | if (!g->keyname) | ||
37 | { | ||
38 | free(g); | ||
39 | return NULL; | ||
40 | } | ||
41 | } | ||
42 | g->object->grabs = eina_list_append(g->object->grabs, g); | ||
43 | if (eina_error_get()) | ||
44 | { | ||
45 | MERR_BAD(); | ||
46 | evas_mem_free(sizeof(Eina_List)); | ||
47 | g->object->grabs = eina_list_append(g->object->grabs, g); | ||
48 | if (eina_error_get()) | ||
49 | { | ||
50 | MERR_FATAL(); | ||
51 | free(g->keyname); | ||
52 | free(g); | ||
53 | return NULL; | ||
54 | } | ||
55 | } | ||
56 | obj->layer->evas->grabs = eina_list_append(obj->layer->evas->grabs, g); | ||
57 | if (eina_error_get()) | ||
58 | { | ||
59 | MERR_BAD(); | ||
60 | evas_mem_free(sizeof(Eina_List)); | ||
61 | obj->layer->evas->grabs = eina_list_append(obj->layer->evas->grabs, g); | ||
62 | if (eina_error_get()) | ||
63 | { | ||
64 | MERR_FATAL(); | ||
65 | g->object->grabs = eina_list_remove(g->object->grabs, g); | ||
66 | free(g->keyname); | ||
67 | free(g); | ||
68 | return NULL; | ||
69 | } | ||
70 | } | ||
71 | return g; | ||
72 | } | ||
73 | |||
74 | static Evas_Key_Grab * | ||
75 | evas_key_grab_find(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive) | ||
76 | { | ||
77 | /* MEM OK */ | ||
78 | Eina_List *l; | ||
79 | Evas_Key_Grab *g; | ||
80 | |||
81 | EINA_LIST_FOREACH(obj->layer->evas->grabs, l, g) | ||
82 | { | ||
83 | if ((g->modifiers == modifiers) && | ||
84 | (g->not_modifiers == not_modifiers) && | ||
85 | (!strcmp(g->keyname, keyname))) | ||
86 | { | ||
87 | if ((exclusive) || (obj == g->object)) return g; | ||
88 | } | ||
89 | } | ||
90 | return NULL; | ||
91 | } | ||
92 | |||
93 | /* local calls */ | ||
94 | |||
95 | void | ||
96 | evas_object_grabs_cleanup(Evas_Object *obj) | ||
97 | { | ||
98 | if (obj->layer->evas->walking_grabs) | ||
99 | { | ||
100 | Eina_List *l; | ||
101 | Evas_Key_Grab *g; | ||
102 | |||
103 | EINA_LIST_FOREACH(obj->grabs, l, g) | ||
104 | g->delete_me = EINA_TRUE; | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | while (obj->grabs) | ||
109 | { | ||
110 | Evas_Key_Grab *g = obj->grabs->data; | ||
111 | if (g->keyname) free(g->keyname); | ||
112 | free(g); | ||
113 | obj->layer->evas->grabs = eina_list_remove(obj->layer->evas->grabs, | ||
114 | g); | ||
115 | obj->grabs = eina_list_remove(obj->grabs, g); | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
120 | void | ||
121 | evas_key_grab_free(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers) | ||
122 | { | ||
123 | /* MEM OK */ | ||
124 | Evas_Key_Grab *g; | ||
125 | |||
126 | g = evas_key_grab_find(obj, keyname, modifiers, not_modifiers, 0); | ||
127 | if (!g) return; | ||
128 | g->object->grabs = eina_list_remove(g->object->grabs, g); | ||
129 | obj->layer->evas->grabs = eina_list_remove(obj->layer->evas->grabs, g); | ||
130 | if (g->keyname) free(g->keyname); | ||
131 | free(g); | ||
132 | } | ||
133 | |||
134 | /* public calls */ | ||
135 | |||
136 | EAPI Eina_Bool | ||
137 | evas_object_key_grab(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive) | ||
138 | { | ||
139 | /* MEM OK */ | ||
140 | Evas_Key_Grab *g; | ||
141 | |||
142 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
143 | return EINA_FALSE; | ||
144 | MAGIC_CHECK_END(); | ||
145 | if (!keyname) return EINA_FALSE; | ||
146 | if (exclusive) | ||
147 | { | ||
148 | g = evas_key_grab_find(obj, keyname, modifiers, not_modifiers, | ||
149 | exclusive); | ||
150 | if (g) return EINA_FALSE; | ||
151 | } | ||
152 | g = evas_key_grab_new(obj, keyname, modifiers, not_modifiers, exclusive); | ||
153 | if (!g) return EINA_FALSE; | ||
154 | return EINA_TRUE; | ||
155 | } | ||
156 | |||
157 | EAPI void | ||
158 | evas_object_key_ungrab(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers) | ||
159 | { | ||
160 | /* MEM OK */ | ||
161 | Evas_Key_Grab *g; | ||
162 | |||
163 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
164 | return; | ||
165 | MAGIC_CHECK_END(); | ||
166 | if (!keyname) return; | ||
167 | g = evas_key_grab_find(obj, keyname, modifiers, not_modifiers, 0); | ||
168 | if (!g) return; | ||
169 | if (g->object->layer->evas->walking_grabs) | ||
170 | { | ||
171 | if (!g->delete_me) | ||
172 | { | ||
173 | g->object->layer->evas->delete_grabs++; | ||
174 | g->delete_me = EINA_TRUE; | ||
175 | } | ||
176 | } | ||
177 | else | ||
178 | evas_key_grab_free(g->object, keyname, modifiers, not_modifiers); | ||
179 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_layer.c b/libraries/evas/src/lib/canvas/evas_layer.c new file mode 100644 index 0000000..54e9907 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_layer.c | |||
@@ -0,0 +1,193 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | static void _evas_layer_free(Evas_Layer *lay); | ||
5 | |||
6 | void | ||
7 | evas_object_inject(Evas_Object *obj, Evas *e) | ||
8 | { | ||
9 | Evas_Layer *lay; | ||
10 | |||
11 | if (obj->in_layer) return; | ||
12 | lay = evas_layer_find(e, obj->cur.layer); | ||
13 | if (!lay) | ||
14 | { | ||
15 | lay = evas_layer_new(e); | ||
16 | lay->layer = obj->cur.layer; | ||
17 | evas_layer_add(lay); | ||
18 | } | ||
19 | lay->objects = (Evas_Object *)eina_inlist_append(EINA_INLIST_GET(lay->objects), EINA_INLIST_GET(obj)); | ||
20 | lay->usage++; | ||
21 | obj->layer = lay; | ||
22 | obj->in_layer = 1; | ||
23 | } | ||
24 | |||
25 | void | ||
26 | evas_object_release(Evas_Object *obj, int clean_layer) | ||
27 | { | ||
28 | if (!obj->in_layer) return; | ||
29 | obj->layer->objects = (Evas_Object *)eina_inlist_remove(EINA_INLIST_GET(obj->layer->objects), EINA_INLIST_GET(obj)); | ||
30 | obj->layer->usage--; | ||
31 | if (clean_layer) | ||
32 | { | ||
33 | if (obj->layer->usage <= 0) | ||
34 | { | ||
35 | evas_layer_del(obj->layer); | ||
36 | _evas_layer_free(obj->layer); | ||
37 | } | ||
38 | } | ||
39 | obj->layer = NULL; | ||
40 | obj->in_layer = 0; | ||
41 | } | ||
42 | |||
43 | Evas_Layer * | ||
44 | evas_layer_new(Evas *e) | ||
45 | { | ||
46 | Evas_Layer *lay; | ||
47 | |||
48 | lay = calloc(1, sizeof(Evas_Layer)); | ||
49 | if (!lay) return NULL; | ||
50 | lay->evas = e; | ||
51 | return lay; | ||
52 | } | ||
53 | |||
54 | static void | ||
55 | _evas_layer_free(Evas_Layer *lay) | ||
56 | { | ||
57 | free(lay); | ||
58 | } | ||
59 | |||
60 | void | ||
61 | evas_layer_pre_free(Evas_Layer *lay) | ||
62 | { | ||
63 | Evas_Object *obj; | ||
64 | |||
65 | EINA_INLIST_FOREACH(lay->objects, obj) | ||
66 | { | ||
67 | if ((!obj->smart.parent) && (!obj->delete_me)) | ||
68 | evas_object_del(obj); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | void | ||
73 | evas_layer_free_objects(Evas_Layer *lay) | ||
74 | { | ||
75 | while (lay->objects) | ||
76 | { | ||
77 | Evas_Object *obj; | ||
78 | |||
79 | obj = (Evas_Object *)lay->objects; | ||
80 | evas_object_free(obj, 0); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void | ||
85 | evas_layer_clean(Evas *e) | ||
86 | { | ||
87 | Evas_Layer *tmp; | ||
88 | |||
89 | while (e->layers) | ||
90 | { | ||
91 | tmp = e->layers; | ||
92 | evas_layer_del(tmp); | ||
93 | _evas_layer_free(tmp); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | Evas_Layer * | ||
98 | evas_layer_find(Evas *e, short layer_num) | ||
99 | { | ||
100 | Evas_Layer *layer; | ||
101 | |||
102 | EINA_INLIST_FOREACH(e->layers, layer) | ||
103 | { | ||
104 | if (layer->layer == layer_num) return layer; | ||
105 | } | ||
106 | return NULL; | ||
107 | } | ||
108 | |||
109 | void | ||
110 | evas_layer_add(Evas_Layer *lay) | ||
111 | { | ||
112 | Evas_Layer *layer; | ||
113 | |||
114 | EINA_INLIST_FOREACH(lay->evas->layers, layer) | ||
115 | { | ||
116 | if (layer->layer > lay->layer) | ||
117 | { | ||
118 | lay->evas->layers = (Evas_Layer *)eina_inlist_prepend_relative(EINA_INLIST_GET(lay->evas->layers), | ||
119 | EINA_INLIST_GET(lay), | ||
120 | EINA_INLIST_GET(layer)); | ||
121 | return; | ||
122 | } | ||
123 | } | ||
124 | lay->evas->layers = (Evas_Layer *)eina_inlist_append(EINA_INLIST_GET(lay->evas->layers), EINA_INLIST_GET(lay)); | ||
125 | } | ||
126 | |||
127 | void | ||
128 | evas_layer_del(Evas_Layer *lay) | ||
129 | { | ||
130 | Evas *e; | ||
131 | |||
132 | e = lay->evas; | ||
133 | e->layers = (Evas_Layer *)eina_inlist_remove(EINA_INLIST_GET(e->layers), EINA_INLIST_GET(lay)); | ||
134 | } | ||
135 | |||
136 | /* public functions */ | ||
137 | |||
138 | EAPI void | ||
139 | evas_object_layer_set(Evas_Object *obj, short l) | ||
140 | { | ||
141 | Evas *e; | ||
142 | |||
143 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
144 | return; | ||
145 | MAGIC_CHECK_END(); | ||
146 | if (obj->delete_me) return; | ||
147 | if (evas_object_intercept_call_layer_set(obj, l)) return; | ||
148 | if (obj->smart.parent) return; | ||
149 | if (obj->cur.layer == l) | ||
150 | { | ||
151 | evas_object_raise(obj); | ||
152 | return; | ||
153 | } | ||
154 | e = obj->layer->evas; | ||
155 | evas_object_release(obj, 1); | ||
156 | obj->cur.layer = l; | ||
157 | evas_object_inject(obj, e); | ||
158 | obj->restack = 1; | ||
159 | evas_object_change(obj); | ||
160 | if (obj->clip.clipees) | ||
161 | { | ||
162 | evas_object_inform_call_restack(obj); | ||
163 | return; | ||
164 | } | ||
165 | evas_object_change(obj); | ||
166 | if (!obj->smart.smart) | ||
167 | { | ||
168 | if (evas_object_is_in_output_rect(obj, | ||
169 | obj->layer->evas->pointer.x, | ||
170 | obj->layer->evas->pointer.y, 1, 1) && | ||
171 | obj->cur.visible) | ||
172 | if (eina_list_data_find(obj->layer->evas->pointer.object.in, obj)) | ||
173 | evas_event_feed_mouse_move(obj->layer->evas, | ||
174 | obj->layer->evas->pointer.x, | ||
175 | obj->layer->evas->pointer.y, | ||
176 | obj->layer->evas->last_timestamp, | ||
177 | NULL); | ||
178 | } | ||
179 | evas_object_inform_call_restack(obj); | ||
180 | } | ||
181 | |||
182 | EAPI short | ||
183 | evas_object_layer_get(const Evas_Object *obj) | ||
184 | { | ||
185 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
186 | return 0; | ||
187 | MAGIC_CHECK_END(); | ||
188 | if (obj->smart.parent) | ||
189 | { | ||
190 | return obj->smart.parent->cur.layer; | ||
191 | } | ||
192 | return obj->cur.layer; | ||
193 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_main.c b/libraries/evas/src/lib/canvas/evas_main.c new file mode 100644 index 0000000..0a37b2c --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_main.c | |||
@@ -0,0 +1,671 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | #include "evas_cs.h" | ||
4 | |||
5 | #ifdef LKDEBUG | ||
6 | EAPI Eina_Bool lockdebug = EINA_FALSE; | ||
7 | EAPI int lockmax = 0; | ||
8 | #endif | ||
9 | |||
10 | static int _evas_init_count = 0; | ||
11 | int _evas_log_dom_global = -1; | ||
12 | EAPI int | ||
13 | evas_init(void) | ||
14 | { | ||
15 | if (++_evas_init_count != 1) | ||
16 | return _evas_init_count; | ||
17 | |||
18 | #ifdef LKDEBUG | ||
19 | if (getenv("EVAS_LOCK_DEBUG")) | ||
20 | { | ||
21 | lockdebug = EINA_TRUE; | ||
22 | lockmax = atoi(getenv("EVAS_LOCK_DEBUG")); | ||
23 | } | ||
24 | #endif | ||
25 | |||
26 | #ifdef HAVE_EVIL | ||
27 | if (!evil_init()) | ||
28 | return --_evas_init_count; | ||
29 | #endif | ||
30 | |||
31 | if (!eina_init()) | ||
32 | goto shutdown_evil; | ||
33 | |||
34 | _evas_log_dom_global = eina_log_domain_register | ||
35 | ("evas_main", EVAS_DEFAULT_LOG_COLOR); | ||
36 | if (_evas_log_dom_global < 0) | ||
37 | { | ||
38 | EINA_LOG_ERR("Can not create a module log domain."); | ||
39 | goto shutdown_eina; | ||
40 | } | ||
41 | |||
42 | evas_module_init(); | ||
43 | #ifdef BUILD_ASYNC_EVENTS | ||
44 | if (!evas_async_events_init()) | ||
45 | goto shutdown_module; | ||
46 | #endif | ||
47 | #ifdef EVAS_CSERVE | ||
48 | if (getenv("EVAS_CSERVE")) evas_cserve_init(); | ||
49 | #endif | ||
50 | #ifdef BUILD_ASYNC_PRELOAD | ||
51 | _evas_preload_thread_init(); | ||
52 | #endif | ||
53 | #ifdef EVAS_FRAME_QUEUING | ||
54 | evas_common_frameq_init(); | ||
55 | #endif | ||
56 | |||
57 | return _evas_init_count; | ||
58 | |||
59 | #ifdef BUILD_ASYNC_EVENTS | ||
60 | shutdown_module: | ||
61 | evas_module_shutdown(); | ||
62 | eina_log_domain_unregister(_evas_log_dom_global); | ||
63 | #endif | ||
64 | shutdown_eina: | ||
65 | eina_shutdown(); | ||
66 | shutdown_evil: | ||
67 | #ifdef HAVE_EVIL | ||
68 | evil_shutdown(); | ||
69 | #endif | ||
70 | |||
71 | return --_evas_init_count; | ||
72 | } | ||
73 | |||
74 | EAPI int | ||
75 | evas_shutdown(void) | ||
76 | { | ||
77 | if (--_evas_init_count != 0) | ||
78 | return _evas_init_count; | ||
79 | |||
80 | #ifdef EVAS_FRAME_QUEUING | ||
81 | if (evas_common_frameq_enabled()) | ||
82 | { | ||
83 | evas_common_frameq_finish(); | ||
84 | evas_common_frameq_destroy(); | ||
85 | } | ||
86 | #endif | ||
87 | #ifdef BUILD_ASYNC_EVENTS | ||
88 | _evas_preload_thread_shutdown(); | ||
89 | #endif | ||
90 | #ifdef EVAS_CSERVE | ||
91 | if (getenv("EVAS_CSERVE")) evas_cserve_shutdown(); | ||
92 | #endif | ||
93 | #ifdef BUILD_ASYNC_EVENTS | ||
94 | evas_async_events_shutdown(); | ||
95 | #endif | ||
96 | evas_font_dir_cache_free(); | ||
97 | evas_common_shutdown(); | ||
98 | evas_module_shutdown(); | ||
99 | eina_log_domain_unregister(_evas_log_dom_global); | ||
100 | eina_shutdown(); | ||
101 | #ifdef HAVE_EVIL | ||
102 | evil_shutdown(); | ||
103 | #endif | ||
104 | |||
105 | return _evas_init_count; | ||
106 | } | ||
107 | |||
108 | |||
109 | EAPI Evas * | ||
110 | evas_new(void) | ||
111 | { | ||
112 | Evas *e; | ||
113 | |||
114 | e = calloc(1, sizeof(Evas)); | ||
115 | if (!e) return NULL; | ||
116 | |||
117 | e->magic = MAGIC_EVAS; | ||
118 | e->output.render_method = RENDER_METHOD_INVALID; | ||
119 | e->viewport.w = 1; | ||
120 | e->viewport.h = 1; | ||
121 | e->hinting = EVAS_FONT_HINTING_BYTECODE; | ||
122 | e->name_hash = eina_hash_string_superfast_new(NULL); | ||
123 | eina_clist_init(&e->calc_list); | ||
124 | eina_clist_init(&e->calc_done); | ||
125 | |||
126 | #define EVAS_ARRAY_SET(E, Array) \ | ||
127 | eina_array_step_set(&E->Array, sizeof (E->Array), 4096); | ||
128 | |||
129 | EVAS_ARRAY_SET(e, delete_objects); | ||
130 | EVAS_ARRAY_SET(e, active_objects); | ||
131 | EVAS_ARRAY_SET(e, restack_objects); | ||
132 | EVAS_ARRAY_SET(e, render_objects); | ||
133 | EVAS_ARRAY_SET(e, pending_objects); | ||
134 | EVAS_ARRAY_SET(e, obscuring_objects); | ||
135 | EVAS_ARRAY_SET(e, temporary_objects); | ||
136 | EVAS_ARRAY_SET(e, calculate_objects); | ||
137 | EVAS_ARRAY_SET(e, clip_changes); | ||
138 | |||
139 | #undef EVAS_ARRAY_SET | ||
140 | |||
141 | return e; | ||
142 | } | ||
143 | |||
144 | EAPI void | ||
145 | evas_free(Evas *e) | ||
146 | { | ||
147 | Eina_Rectangle *r; | ||
148 | Evas_Coord_Touch_Point *touch_point; | ||
149 | Evas_Layer *lay; | ||
150 | int i; | ||
151 | int del; | ||
152 | |||
153 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
154 | return; | ||
155 | MAGIC_CHECK_END(); | ||
156 | |||
157 | #ifdef EVAS_FRAME_QUEUING | ||
158 | evas_common_frameq_flush(); | ||
159 | #endif | ||
160 | |||
161 | if (e->walking_list == 0) evas_render_idle_flush(e); | ||
162 | |||
163 | if (e->walking_list > 0) return; | ||
164 | |||
165 | if (e->callbacks) | ||
166 | { | ||
167 | if (e->callbacks->deletions_waiting) return; | ||
168 | |||
169 | e->callbacks->deletions_waiting = 0; | ||
170 | evas_event_callback_list_post_free(&e->callbacks->callbacks); | ||
171 | if (!e->callbacks->callbacks) | ||
172 | { | ||
173 | free(e->callbacks); | ||
174 | e->callbacks = NULL; | ||
175 | } | ||
176 | |||
177 | _evas_post_event_callback_free(e); | ||
178 | } | ||
179 | |||
180 | del = 1; | ||
181 | e->walking_list++; | ||
182 | e->cleanup = 1; | ||
183 | while (del) | ||
184 | { | ||
185 | del = 0; | ||
186 | EINA_INLIST_FOREACH(e->layers, lay) | ||
187 | { | ||
188 | Evas_Object *o; | ||
189 | |||
190 | evas_layer_pre_free(lay); | ||
191 | |||
192 | EINA_INLIST_FOREACH(lay->objects, o) | ||
193 | { | ||
194 | if ((o->callbacks) && (o->callbacks->walking_list)) | ||
195 | { | ||
196 | /* Defer free */ | ||
197 | e->delete_me = 1; | ||
198 | e->walking_list--; | ||
199 | return; | ||
200 | } | ||
201 | if (!o->delete_me) | ||
202 | del = 1; | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | EINA_INLIST_FOREACH(e->layers, lay) | ||
207 | evas_layer_free_objects(lay); | ||
208 | evas_layer_clean(e); | ||
209 | |||
210 | e->walking_list--; | ||
211 | |||
212 | evas_font_path_clear(e); | ||
213 | e->pointer.object.in = eina_list_free(e->pointer.object.in); | ||
214 | |||
215 | if (e->name_hash) eina_hash_free(e->name_hash); | ||
216 | e->name_hash = NULL; | ||
217 | |||
218 | EINA_LIST_FREE(e->damages, r) | ||
219 | eina_rectangle_free(r); | ||
220 | EINA_LIST_FREE(e->obscures, r) | ||
221 | eina_rectangle_free(r); | ||
222 | |||
223 | evas_fonts_zero_free(e); | ||
224 | |||
225 | evas_event_callback_all_del(e); | ||
226 | evas_event_callback_cleanup(e); | ||
227 | |||
228 | if (e->engine.func) | ||
229 | { | ||
230 | e->engine.func->context_free(e->engine.data.output, e->engine.data.context); | ||
231 | e->engine.func->output_free(e->engine.data.output); | ||
232 | e->engine.func->info_free(e, e->engine.info); | ||
233 | } | ||
234 | |||
235 | for (i = 0; i < e->modifiers.mod.count; i++) | ||
236 | free(e->modifiers.mod.list[i]); | ||
237 | if (e->modifiers.mod.list) free(e->modifiers.mod.list); | ||
238 | |||
239 | for (i = 0; i < e->locks.lock.count; i++) | ||
240 | free(e->locks.lock.list[i]); | ||
241 | if (e->locks.lock.list) free(e->locks.lock.list); | ||
242 | |||
243 | if (e->engine.module) evas_module_unref(e->engine.module); | ||
244 | |||
245 | eina_array_flush(&e->delete_objects); | ||
246 | eina_array_flush(&e->active_objects); | ||
247 | eina_array_flush(&e->restack_objects); | ||
248 | eina_array_flush(&e->render_objects); | ||
249 | eina_array_flush(&e->pending_objects); | ||
250 | eina_array_flush(&e->obscuring_objects); | ||
251 | eina_array_flush(&e->temporary_objects); | ||
252 | eina_array_flush(&e->calculate_objects); | ||
253 | eina_array_flush(&e->clip_changes); | ||
254 | |||
255 | EINA_LIST_FREE(e->touch_points, touch_point) | ||
256 | free(touch_point); | ||
257 | |||
258 | e->magic = 0; | ||
259 | free(e); | ||
260 | } | ||
261 | |||
262 | EAPI void | ||
263 | evas_output_method_set(Evas *e, int render_method) | ||
264 | { | ||
265 | Evas_Module *em; | ||
266 | |||
267 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
268 | return; | ||
269 | MAGIC_CHECK_END(); | ||
270 | |||
271 | /* if our engine to set it to is invalid - abort */ | ||
272 | if (render_method == RENDER_METHOD_INVALID) return; | ||
273 | /* if the engine is already set up - abort */ | ||
274 | if (e->output.render_method != RENDER_METHOD_INVALID) return; | ||
275 | /* Request the right engine. */ | ||
276 | em = evas_module_engine_get(render_method); | ||
277 | if (!em) return ; | ||
278 | if (em->id_engine != render_method) return; | ||
279 | if (!evas_module_load(em)) return; | ||
280 | |||
281 | /* set the correct render */ | ||
282 | e->output.render_method = render_method; | ||
283 | e->engine.func = (em->functions); | ||
284 | evas_module_use(em); | ||
285 | if (e->engine.module) evas_module_unref(e->engine.module); | ||
286 | e->engine.module = em; | ||
287 | evas_module_ref(em); | ||
288 | /* get the engine info struct */ | ||
289 | if (e->engine.func->info) e->engine.info = e->engine.func->info(e); | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | EAPI int | ||
294 | evas_output_method_get(const Evas *e) | ||
295 | { | ||
296 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
297 | return RENDER_METHOD_INVALID; | ||
298 | MAGIC_CHECK_END(); | ||
299 | |||
300 | return e->output.render_method; | ||
301 | } | ||
302 | |||
303 | EAPI Evas_Engine_Info * | ||
304 | evas_engine_info_get(const Evas *e) | ||
305 | { | ||
306 | Evas_Engine_Info *info; | ||
307 | |||
308 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
309 | return NULL; | ||
310 | MAGIC_CHECK_END(); | ||
311 | |||
312 | if (!e->engine.info) return NULL; | ||
313 | |||
314 | info = e->engine.info; | ||
315 | ((Evas *)e)->engine.info_magic = info->magic; | ||
316 | |||
317 | return info; | ||
318 | } | ||
319 | |||
320 | EAPI Eina_Bool | ||
321 | evas_engine_info_set(Evas *e, Evas_Engine_Info *info) | ||
322 | { | ||
323 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
324 | return EINA_FALSE; | ||
325 | MAGIC_CHECK_END(); | ||
326 | if (!info) return EINA_FALSE; | ||
327 | if (info != e->engine.info) return EINA_FALSE; | ||
328 | if (info->magic != e->engine.info_magic) return EINA_FALSE; | ||
329 | return (Eina_Bool)e->engine.func->setup(e, info); | ||
330 | } | ||
331 | |||
332 | EAPI void | ||
333 | evas_output_size_set(Evas *e, int w, int h) | ||
334 | { | ||
335 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
336 | return; | ||
337 | MAGIC_CHECK_END(); | ||
338 | |||
339 | if ((w == e->output.w) && (h == e->output.h)) return; | ||
340 | if (w < 1) w = 1; | ||
341 | if (h < 1) h = 1; | ||
342 | |||
343 | #ifdef EVAS_FRAME_QUEUING | ||
344 | evas_common_frameq_flush(); | ||
345 | #endif | ||
346 | |||
347 | e->output.w = w; | ||
348 | e->output.h = h; | ||
349 | e->output.changed = 1; | ||
350 | e->output_validity++; | ||
351 | e->changed = 1; | ||
352 | evas_render_invalidate(e); | ||
353 | } | ||
354 | |||
355 | EAPI void | ||
356 | evas_output_size_get(const Evas *e, int *w, int *h) | ||
357 | { | ||
358 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
359 | if (w) *w = 0; | ||
360 | if (h) *h = 0; | ||
361 | return; | ||
362 | MAGIC_CHECK_END(); | ||
363 | |||
364 | if (w) *w = e->output.w; | ||
365 | if (h) *h = e->output.h; | ||
366 | } | ||
367 | |||
368 | EAPI void | ||
369 | evas_output_viewport_set(Evas *e, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) | ||
370 | { | ||
371 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
372 | return; | ||
373 | MAGIC_CHECK_END(); | ||
374 | |||
375 | if ((x == e->viewport.x) && (y == e->viewport.y) && | ||
376 | (w == e->viewport.w) && (h == e->viewport.h)) return; | ||
377 | if (w <= 0) return; | ||
378 | if (h <= 0) return; | ||
379 | if ((x != 0) || (y != 0)) | ||
380 | { | ||
381 | ERR("Compat error. viewport x,y != 0,0 not supported"); | ||
382 | x = 0; | ||
383 | y = 0; | ||
384 | } | ||
385 | e->viewport.x = x; | ||
386 | e->viewport.y = y; | ||
387 | e->viewport.w = w; | ||
388 | e->viewport.h = h; | ||
389 | e->viewport.changed = 1; | ||
390 | e->output_validity++; | ||
391 | e->changed = 1; | ||
392 | } | ||
393 | |||
394 | EAPI void | ||
395 | evas_output_viewport_get(const Evas *e, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) | ||
396 | { | ||
397 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
398 | if (x) *x = 0; | ||
399 | if (y) *y = 0; | ||
400 | if (w) *w = 0; | ||
401 | if (h) *h = 0; | ||
402 | return; | ||
403 | MAGIC_CHECK_END(); | ||
404 | |||
405 | if (x) *x = e->viewport.x; | ||
406 | if (y) *y = e->viewport.y; | ||
407 | if (w) *w = e->viewport.w; | ||
408 | if (h) *h = e->viewport.h; | ||
409 | } | ||
410 | |||
411 | EAPI Evas_Coord | ||
412 | evas_coord_screen_x_to_world(const Evas *e, int x) | ||
413 | { | ||
414 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
415 | return 0; | ||
416 | MAGIC_CHECK_END(); | ||
417 | if (e->output.w == e->viewport.w) return e->viewport.x + x; | ||
418 | return (long long)e->viewport.x + (((long long)x * (long long)e->viewport.w) / (long long)e->output.w); | ||
419 | } | ||
420 | |||
421 | EAPI Evas_Coord | ||
422 | evas_coord_screen_y_to_world(const Evas *e, int y) | ||
423 | { | ||
424 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
425 | return 0; | ||
426 | MAGIC_CHECK_END(); | ||
427 | if (e->output.h == e->viewport.h) return e->viewport.y + y; | ||
428 | return (long long)e->viewport.y + (((long long)y * (long long)e->viewport.h) / (long long)e->output.h); | ||
429 | } | ||
430 | |||
431 | EAPI int | ||
432 | evas_coord_world_x_to_screen(const Evas *e, Evas_Coord x) | ||
433 | { | ||
434 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
435 | return 0; | ||
436 | MAGIC_CHECK_END(); | ||
437 | if (e->output.w == e->viewport.w) return x - e->viewport.x; | ||
438 | return (int)((((long long)x - (long long)e->viewport.x) * (long long)e->output.w) / (long long)e->viewport.w); | ||
439 | } | ||
440 | |||
441 | EAPI int | ||
442 | evas_coord_world_y_to_screen(const Evas *e, Evas_Coord y) | ||
443 | { | ||
444 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
445 | return 0; | ||
446 | MAGIC_CHECK_END(); | ||
447 | if (e->output.h == e->viewport.h) return y - e->viewport.y; | ||
448 | return (int)((((long long)y - (long long)e->viewport.y) * (long long)e->output.h) / (long long)e->viewport.h); | ||
449 | } | ||
450 | |||
451 | EAPI int | ||
452 | evas_render_method_lookup(const char *name) | ||
453 | { | ||
454 | Evas_Module *em; | ||
455 | |||
456 | if (!name) return RENDER_METHOD_INVALID; | ||
457 | /* search on the engines list for the name */ | ||
458 | em = evas_module_find_type(EVAS_MODULE_TYPE_ENGINE, name); | ||
459 | if (!em) return RENDER_METHOD_INVALID; | ||
460 | |||
461 | return em->id_engine; | ||
462 | } | ||
463 | |||
464 | EAPI Eina_List * | ||
465 | evas_render_method_list(void) | ||
466 | { | ||
467 | return evas_module_engine_list(); | ||
468 | } | ||
469 | |||
470 | EAPI void | ||
471 | evas_render_method_list_free(Eina_List *list) | ||
472 | { | ||
473 | eina_list_free(list); | ||
474 | } | ||
475 | |||
476 | EAPI Eina_Bool | ||
477 | evas_object_image_extension_can_load_get(const char *file) | ||
478 | { | ||
479 | const char *tmp; | ||
480 | Eina_Bool result; | ||
481 | |||
482 | tmp = eina_stringshare_add(file); | ||
483 | result = evas_common_extension_can_load_get(tmp); | ||
484 | eina_stringshare_del(tmp); | ||
485 | |||
486 | return result; | ||
487 | } | ||
488 | |||
489 | EAPI Eina_Bool | ||
490 | evas_object_image_extension_can_load_fast_get(const char *file) | ||
491 | { | ||
492 | return evas_common_extension_can_load_get(file); | ||
493 | } | ||
494 | |||
495 | EAPI void | ||
496 | evas_pointer_output_xy_get(const Evas *e, int *x, int *y) | ||
497 | { | ||
498 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
499 | if (x) *x = 0; | ||
500 | if (y) *y = 0; | ||
501 | return; | ||
502 | MAGIC_CHECK_END(); | ||
503 | if (x) *x = e->pointer.x; | ||
504 | if (y) *y = e->pointer.y; | ||
505 | } | ||
506 | |||
507 | EAPI void | ||
508 | evas_pointer_canvas_xy_get(const Evas *e, Evas_Coord *x, Evas_Coord *y) | ||
509 | { | ||
510 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
511 | if (x) *x = 0; | ||
512 | if (y) *y = 0; | ||
513 | return; | ||
514 | MAGIC_CHECK_END(); | ||
515 | if (x) *x = e->pointer.x; | ||
516 | if (y) *y = e->pointer.y; | ||
517 | } | ||
518 | |||
519 | EAPI int | ||
520 | evas_pointer_button_down_mask_get(const Evas *e) | ||
521 | { | ||
522 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
523 | return 0; | ||
524 | MAGIC_CHECK_END(); | ||
525 | return (int)e->pointer.button; | ||
526 | } | ||
527 | |||
528 | EAPI Eina_Bool | ||
529 | evas_pointer_inside_get(const Evas *e) | ||
530 | { | ||
531 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
532 | return 0; | ||
533 | MAGIC_CHECK_END(); | ||
534 | return (int)e->pointer.inside; | ||
535 | } | ||
536 | |||
537 | EAPI void | ||
538 | evas_data_attach_set(Evas *e, void *data) | ||
539 | { | ||
540 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
541 | return; | ||
542 | MAGIC_CHECK_END(); | ||
543 | e->attach_data = data; | ||
544 | } | ||
545 | |||
546 | EAPI void * | ||
547 | evas_data_attach_get(const Evas *e) | ||
548 | { | ||
549 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
550 | return NULL; | ||
551 | MAGIC_CHECK_END(); | ||
552 | return e->attach_data; | ||
553 | } | ||
554 | |||
555 | EAPI void | ||
556 | evas_focus_in(Evas *e) | ||
557 | { | ||
558 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
559 | return; | ||
560 | MAGIC_CHECK_END(); | ||
561 | if (e->focus) return; | ||
562 | e->focus = 1; | ||
563 | evas_event_callback_call(e, EVAS_CALLBACK_CANVAS_FOCUS_IN, NULL); | ||
564 | } | ||
565 | |||
566 | EAPI void | ||
567 | evas_focus_out(Evas *e) | ||
568 | { | ||
569 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
570 | return; | ||
571 | MAGIC_CHECK_END(); | ||
572 | if (!e->focus) return; | ||
573 | e->focus = 0; | ||
574 | evas_event_callback_call(e, EVAS_CALLBACK_CANVAS_FOCUS_OUT, NULL); | ||
575 | } | ||
576 | |||
577 | EAPI Eina_Bool | ||
578 | evas_focus_state_get(const Evas *e) | ||
579 | { | ||
580 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
581 | return 0; | ||
582 | MAGIC_CHECK_END(); | ||
583 | return e->focus; | ||
584 | } | ||
585 | |||
586 | EAPI void | ||
587 | evas_nochange_push(Evas *e) | ||
588 | { | ||
589 | e->nochange++; | ||
590 | } | ||
591 | |||
592 | EAPI void | ||
593 | evas_nochange_pop(Evas *e) | ||
594 | { | ||
595 | e->nochange--; | ||
596 | } | ||
597 | |||
598 | void | ||
599 | _evas_walk(Evas *e) | ||
600 | { | ||
601 | e->walking_list++; | ||
602 | } | ||
603 | |||
604 | void | ||
605 | _evas_unwalk(Evas *e) | ||
606 | { | ||
607 | e->walking_list--; | ||
608 | if ((e->walking_list == 0) && (e->delete_me)) evas_free(e); | ||
609 | } | ||
610 | |||
611 | EAPI const char * | ||
612 | evas_load_error_str(Evas_Load_Error error) | ||
613 | { | ||
614 | switch (error) | ||
615 | { | ||
616 | case EVAS_LOAD_ERROR_NONE: | ||
617 | return "No error on load"; | ||
618 | case EVAS_LOAD_ERROR_GENERIC: | ||
619 | return "A non-specific error occurred"; | ||
620 | case EVAS_LOAD_ERROR_DOES_NOT_EXIST: | ||
621 | return "File (or file path) does not exist"; | ||
622 | case EVAS_LOAD_ERROR_PERMISSION_DENIED: | ||
623 | return "Permission deinied to an existing file (or path)"; | ||
624 | case EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED: | ||
625 | return "Allocation of resources failure prevented load"; | ||
626 | case EVAS_LOAD_ERROR_CORRUPT_FILE: | ||
627 | return "File corrupt (but was detected as a known format)"; | ||
628 | case EVAS_LOAD_ERROR_UNKNOWN_FORMAT: | ||
629 | return "File is not a known format"; | ||
630 | default: | ||
631 | return "Unknown error"; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | EAPI void | ||
636 | evas_color_hsv_to_rgb(float h, float s, float v, int *r, int *g, int *b) | ||
637 | { | ||
638 | evas_common_convert_color_hsv_to_rgb(h, s, v, r, g, b); | ||
639 | } | ||
640 | |||
641 | EAPI void | ||
642 | evas_color_rgb_to_hsv(int r, int g, int b, float *h, float *s, float *v) | ||
643 | { | ||
644 | evas_common_convert_color_rgb_to_hsv(r, g, b, h, s, v); | ||
645 | } | ||
646 | |||
647 | EAPI void | ||
648 | evas_color_argb_premul(int a, int *r, int *g, int *b) | ||
649 | { | ||
650 | evas_common_convert_color_argb_premul(a, r, g, b); | ||
651 | } | ||
652 | |||
653 | EAPI void | ||
654 | evas_color_argb_unpremul(int a, int *r, int *g, int *b) | ||
655 | { | ||
656 | evas_common_convert_color_argb_unpremul(a, r, g, b); | ||
657 | } | ||
658 | |||
659 | EAPI void | ||
660 | evas_data_argb_premul(unsigned int *data, unsigned int len) | ||
661 | { | ||
662 | if (!data || (len < 1)) return; | ||
663 | evas_common_convert_argb_premul(data, len); | ||
664 | } | ||
665 | |||
666 | EAPI void | ||
667 | evas_data_argb_unpremul(unsigned int *data, unsigned int len) | ||
668 | { | ||
669 | if (!data || (len < 1)) return; | ||
670 | evas_common_convert_argb_unpremul(data, len); | ||
671 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_map.c b/libraries/evas/src/lib/canvas/evas_map.c new file mode 100644 index 0000000..fca8b3a --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_map.c | |||
@@ -0,0 +1,1031 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | #include <math.h> | ||
4 | |||
5 | static void | ||
6 | _evas_map_calc_geom_change(Evas_Object *obj) | ||
7 | { | ||
8 | int is, was = 0, pass = 0; | ||
9 | |||
10 | evas_object_change(obj); | ||
11 | evas_object_clip_dirty(obj); | ||
12 | if (obj->layer->evas->events_frozen <= 0) | ||
13 | { | ||
14 | evas_object_recalc_clippees(obj); | ||
15 | if (!pass) | ||
16 | { | ||
17 | if (!obj->smart.smart) | ||
18 | { | ||
19 | is = evas_object_is_in_output_rect(obj, | ||
20 | obj->layer->evas->pointer.x, | ||
21 | obj->layer->evas->pointer.y, 1, 1); | ||
22 | if ((is ^ was) && obj->cur.visible) | ||
23 | evas_event_feed_mouse_move(obj->layer->evas, | ||
24 | obj->layer->evas->pointer.x, | ||
25 | obj->layer->evas->pointer.y, | ||
26 | obj->layer->evas->last_timestamp, | ||
27 | NULL); | ||
28 | } | ||
29 | } | ||
30 | } | ||
31 | evas_object_inform_call_move(obj); | ||
32 | evas_object_inform_call_resize(obj); | ||
33 | } | ||
34 | |||
35 | static void | ||
36 | _evas_map_calc_map_geometry(Evas_Object *obj) | ||
37 | { | ||
38 | Evas_Coord x1, x2, y1, y2; | ||
39 | const Evas_Map_Point *p, *p_end; | ||
40 | Eina_Bool ch = EINA_FALSE; | ||
41 | |||
42 | if (!obj->cur.map) return; | ||
43 | |||
44 | // WARN: Do not merge below code to SLP until it is fixed. | ||
45 | // It has an infinite loop bug. | ||
46 | if (obj->prev.map) | ||
47 | { | ||
48 | // FIXME: this causes an infinite loop somewhere... hard to debug | ||
49 | if (obj->prev.map->count == obj->cur.map->count) | ||
50 | { | ||
51 | const Evas_Map_Point *p2; | ||
52 | |||
53 | p = obj->cur.map->points; | ||
54 | p_end = p + obj->cur.map->count; | ||
55 | p2 = obj->prev.map->points; | ||
56 | |||
57 | for (; p < p_end; p++, p2++) | ||
58 | { | ||
59 | if ((p->a != p2->a) || | ||
60 | (p->r != p2->r) || | ||
61 | (p->g != p2->g) || | ||
62 | (p->b != p2->b)) | ||
63 | { | ||
64 | ch = 1; | ||
65 | break; | ||
66 | } | ||
67 | if ((p->x != p2->x) || | ||
68 | (p->y != p2->y) || | ||
69 | (p->z != p2->z)) | ||
70 | { | ||
71 | ch = 1; | ||
72 | break; | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | else | ||
77 | ch = 1; | ||
78 | } | ||
79 | else | ||
80 | ch = 1; | ||
81 | |||
82 | p = obj->cur.map->points; | ||
83 | p_end = p + obj->cur.map->count; | ||
84 | x1 = lround(p->x); | ||
85 | x2 = lround(p->x); | ||
86 | y1 = lround(p->y); | ||
87 | y2 = lround(p->y); | ||
88 | p++; | ||
89 | for (; p < p_end; p++) | ||
90 | { | ||
91 | if (p->x < x1) x1 = p->x; | ||
92 | if (p->x > x2) x2 = p->x; | ||
93 | if (p->y < y1) y1 = p->y; | ||
94 | if (p->y > y2) y2 = p->y; | ||
95 | } | ||
96 | // this causes clip-out bugs now mapped objs canbe opaque!!! | ||
97 | // // add 1 pixel of fuzz around the map region to ensure updates are correct | ||
98 | // x1 -= 1; y1 -= 1; | ||
99 | // x2 += 1; y2 += 1; | ||
100 | if (obj->cur.map->normal_geometry.x != x1) ch = 1; | ||
101 | if (obj->cur.map->normal_geometry.y != y1) ch = 1; | ||
102 | if (obj->cur.map->normal_geometry.w != (x2 - x1)) ch = 1; | ||
103 | if (obj->cur.map->normal_geometry.h != (y2 - y1)) ch = 1; | ||
104 | obj->cur.map->normal_geometry.x = x1; | ||
105 | obj->cur.map->normal_geometry.y = y1; | ||
106 | obj->cur.map->normal_geometry.w = (x2 - x1); | ||
107 | obj->cur.map->normal_geometry.h = (y2 - y1); | ||
108 | if (ch) _evas_map_calc_geom_change(obj); | ||
109 | } | ||
110 | |||
111 | static inline Evas_Map * | ||
112 | _evas_map_new(int count) | ||
113 | { | ||
114 | int i; | ||
115 | int alloc; | ||
116 | Evas_Map *m; | ||
117 | |||
118 | /* Adjust allocation such that: at least 4 points, and always an even | ||
119 | * number: this allows the software engine to work efficiently */ | ||
120 | alloc = (count < 4) ? 4 : count; | ||
121 | if (alloc & 0x1) alloc ++; | ||
122 | |||
123 | m = calloc(1, sizeof(Evas_Map) + (alloc * sizeof(Evas_Map_Point))); | ||
124 | if (!m) return NULL; | ||
125 | m->count = count; | ||
126 | m->persp.foc = 0; | ||
127 | m->alpha = 1; | ||
128 | m->smooth = 1; | ||
129 | m->magic = MAGIC_MAP; | ||
130 | for (i = 0; i < count; i++) | ||
131 | { | ||
132 | m->points[i].r = 255; | ||
133 | m->points[i].g = 255; | ||
134 | m->points[i].b = 255; | ||
135 | m->points[i].a = 255; | ||
136 | } | ||
137 | return m; | ||
138 | } | ||
139 | |||
140 | static inline Eina_Bool | ||
141 | _evas_map_copy(Evas_Map *dst, const Evas_Map *src) | ||
142 | { | ||
143 | if (dst->count != src->count) | ||
144 | { | ||
145 | ERR("cannot copy map of different sizes: dst=%i, src=%i", dst->count, src->count); | ||
146 | return EINA_FALSE; | ||
147 | } | ||
148 | memcpy(dst->points, src->points, src->count * sizeof(Evas_Map_Point)); | ||
149 | dst->smooth = src->smooth; | ||
150 | dst->alpha = src->alpha; | ||
151 | dst->persp = src->persp; | ||
152 | return EINA_TRUE; | ||
153 | } | ||
154 | |||
155 | static inline Evas_Map * | ||
156 | _evas_map_dup(const Evas_Map *orig) | ||
157 | { | ||
158 | Evas_Map *copy = _evas_map_new(orig->count); | ||
159 | if (!copy) return NULL; | ||
160 | memcpy(copy->points, orig->points, orig->count * sizeof(Evas_Map_Point)); | ||
161 | copy->smooth = orig->smooth; | ||
162 | copy->alpha = orig->alpha; | ||
163 | copy->persp = orig->persp; | ||
164 | return copy; | ||
165 | } | ||
166 | |||
167 | static inline void | ||
168 | _evas_map_free(Evas_Object *obj, Evas_Map *m) | ||
169 | { | ||
170 | if (obj) | ||
171 | { | ||
172 | if (m->surface) | ||
173 | obj->layer->evas->engine.func->image_map_surface_free | ||
174 | (obj->layer->evas->engine.data.output, m->surface); | ||
175 | } | ||
176 | m->magic = 0; | ||
177 | free(m); | ||
178 | } | ||
179 | |||
180 | /****************************************************************************/ | ||
181 | /* util functions for manipulating maps, so you don't need to know the math */ | ||
182 | /****************************************************************************/ | ||
183 | static inline void | ||
184 | _evas_map_util_points_populate(Evas_Map *m, const Evas_Coord x, const Evas_Coord y, const Evas_Coord w, const Evas_Coord h, const Evas_Coord z) | ||
185 | { | ||
186 | Evas_Map_Point *p = m->points; | ||
187 | int i; | ||
188 | |||
189 | p[0].x = x; | ||
190 | p[0].y = y; | ||
191 | p[0].z = z; | ||
192 | p[0].u = 0.0; | ||
193 | p[0].v = 0.0; | ||
194 | |||
195 | p[1].x = x + w; | ||
196 | p[1].y = y; | ||
197 | p[1].z = z; | ||
198 | p[1].u = w; | ||
199 | p[1].v = 0.0; | ||
200 | |||
201 | p[2].x = x + w; | ||
202 | p[2].y = y + h; | ||
203 | p[2].z = z; | ||
204 | p[2].u = w; | ||
205 | p[2].v = h; | ||
206 | |||
207 | p[3].x = x; | ||
208 | p[3].y = y + h; | ||
209 | p[3].z = z; | ||
210 | p[3].u = 0.0; | ||
211 | p[3].v = h; | ||
212 | |||
213 | for (i = 0; i < 4; i++) | ||
214 | { | ||
215 | p[i].px = p[i].x; | ||
216 | p[i].py = p[i].y; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | Eina_Bool | ||
221 | evas_map_coords_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y, | ||
222 | Evas_Coord *mx, Evas_Coord *my, int grab) | ||
223 | { | ||
224 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
225 | return EINA_FALSE; | ||
226 | MAGIC_CHECK_END(); | ||
227 | |||
228 | int i, j, edges, edge[m->count][2], douv; | ||
229 | Evas_Coord xe[2]; | ||
230 | double u[2] = { 0.0, 0.0 }; | ||
231 | double v[2] = { 0.0, 0.0 }; | ||
232 | |||
233 | if (m->count < 4) return 0; | ||
234 | // FIXME need to handle grab mode and extrapolte coords outside | ||
235 | // map | ||
236 | if (grab) | ||
237 | { | ||
238 | Evas_Coord ymin, ymax; | ||
239 | |||
240 | ymin = m->points[0].y; | ||
241 | ymax = m->points[0].y; | ||
242 | for (i = 1; i < m->count; i++) | ||
243 | { | ||
244 | if (m->points[i].y < ymin) ymin = m->points[i].y; | ||
245 | else if (m->points[i].y > ymax) ymax = m->points[i].y; | ||
246 | } | ||
247 | if (y <= ymin) y = ymin + 1; | ||
248 | if (y >= ymax) y = ymax - 1; | ||
249 | } | ||
250 | edges = 0; | ||
251 | for (i = 0; i < m->count; i++) | ||
252 | { | ||
253 | j = (i + 1) % m->count; | ||
254 | if ((m->points[i].y <= y) && (m->points[j].y > y)) | ||
255 | { | ||
256 | edge[edges][0] = i; | ||
257 | edge[edges][1] = j; | ||
258 | edges++; | ||
259 | } | ||
260 | else if ((m->points[j].y <= y) && (m->points[i].y > y)) | ||
261 | { | ||
262 | edge[edges][0] = j; | ||
263 | edge[edges][1] = i; | ||
264 | edges++; | ||
265 | } | ||
266 | } | ||
267 | douv = 0; | ||
268 | if ((mx) || (my)) douv = 1; | ||
269 | for (i = 0; i < (edges - 1); i+= 2) | ||
270 | { | ||
271 | Evas_Coord yp, yd; | ||
272 | |||
273 | j = i + 1; | ||
274 | yd = m->points[edge[i][1]].y - m->points[edge[i][0]].y; | ||
275 | if (yd > 0) | ||
276 | { | ||
277 | yp = y - m->points[edge[i][0]].y; | ||
278 | xe[0] = m->points[edge[i][1]].x - m->points[edge[i][0]].x; | ||
279 | xe[0] = m->points[edge[i][0]].x + ((xe[0] * yp) / yd); | ||
280 | if (douv) | ||
281 | { | ||
282 | u[0] = m->points[edge[i][1]].u - m->points[edge[i][0]].u; | ||
283 | u[0] = m->points[edge[i][0]].u + ((u[0] * yp) / yd); | ||
284 | v[0] = m->points[edge[i][1]].v - m->points[edge[i][0]].v; | ||
285 | v[0] = m->points[edge[i][0]].v + ((v[0] * yp) / yd); | ||
286 | } | ||
287 | } | ||
288 | else | ||
289 | { | ||
290 | xe[0] = m->points[edge[i][0]].x; | ||
291 | if (douv) | ||
292 | { | ||
293 | u[0] = m->points[edge[i][0]].u; | ||
294 | v[0] = m->points[edge[i][0]].v; | ||
295 | } | ||
296 | } | ||
297 | yd = m->points[edge[j][1]].y - m->points[edge[j][0]].y; | ||
298 | if (yd > 0) | ||
299 | { | ||
300 | yp = y - m->points[edge[j][0]].y; | ||
301 | xe[1] = m->points[edge[j][1]].x - m->points[edge[j][0]].x; | ||
302 | xe[1] = m->points[edge[j][0]].x + ((xe[1] * yp) / yd); | ||
303 | if (douv) | ||
304 | { | ||
305 | u[1] = m->points[edge[j][1]].u - m->points[edge[j][0]].u; | ||
306 | u[1] = m->points[edge[j][0]].u + ((u[1] * yp) / yd); | ||
307 | v[1] = m->points[edge[j][1]].v - m->points[edge[j][0]].v; | ||
308 | v[1] = m->points[edge[j][0]].v + ((v[1] * yp) / yd); | ||
309 | } | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | xe[1] = m->points[edge[j][0]].x; | ||
314 | if (douv) | ||
315 | { | ||
316 | u[1] = m->points[edge[j][0]].u; | ||
317 | v[1] = m->points[edge[j][0]].v; | ||
318 | } | ||
319 | } | ||
320 | if (xe[0] > xe[1]) | ||
321 | { | ||
322 | int ti; | ||
323 | |||
324 | ti = xe[0]; xe[0] = xe[1]; xe[1] = ti; | ||
325 | if (douv) | ||
326 | { | ||
327 | double td; | ||
328 | |||
329 | td = u[0]; u[0] = u[1]; u[1] = td; | ||
330 | td = v[0]; v[0] = v[1]; v[1] = td; | ||
331 | } | ||
332 | } | ||
333 | if ((x >= xe[0]) && (x < xe[1])) | ||
334 | { | ||
335 | if (douv) | ||
336 | { | ||
337 | if (mx) | ||
338 | *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) / | ||
339 | (xe[1] - xe[0])); | ||
340 | if (my) | ||
341 | *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) / | ||
342 | (xe[1] - xe[0])); | ||
343 | } | ||
344 | return EINA_TRUE; | ||
345 | } | ||
346 | if (grab) | ||
347 | { | ||
348 | if (douv) | ||
349 | { | ||
350 | if (mx) | ||
351 | *mx = u[0] + (((x - xe[0]) * (u[1] - u[0])) / | ||
352 | (xe[1] - xe[0])); | ||
353 | if (my) | ||
354 | *my = v[0] + (((x - xe[0]) * (v[1] - v[0])) / | ||
355 | (xe[1] - xe[0])); | ||
356 | } | ||
357 | return EINA_TRUE; | ||
358 | } | ||
359 | } | ||
360 | return EINA_FALSE; | ||
361 | } | ||
362 | |||
363 | Eina_Bool | ||
364 | evas_map_inside_get(const Evas_Map *m, Evas_Coord x, Evas_Coord y) | ||
365 | { | ||
366 | return evas_map_coords_get(m, x, y, NULL, NULL, 0); | ||
367 | } | ||
368 | |||
369 | EAPI void | ||
370 | evas_object_map_enable_set(Evas_Object *obj, Eina_Bool enabled) | ||
371 | { | ||
372 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
373 | return; | ||
374 | MAGIC_CHECK_END(); | ||
375 | |||
376 | enabled = !!enabled; | ||
377 | if (obj->cur.usemap == enabled) return; | ||
378 | obj->cur.usemap = enabled; | ||
379 | if (enabled) | ||
380 | { | ||
381 | if (!obj->cur.map) | ||
382 | obj->cur.map = _evas_map_new(4); | ||
383 | evas_object_mapped_clip_across_mark(obj); | ||
384 | // obj->cur.map->normal_geometry = obj->cur.geometry; | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | if (obj->cur.map) | ||
389 | { | ||
390 | _evas_map_calc_geom_change(obj); | ||
391 | evas_object_mapped_clip_across_mark(obj); | ||
392 | //FIXME: Since the last frame is not updated when map is | ||
393 | //disabled, afterimage problem is happened in s/w rendering. | ||
394 | //Need to find out the fundamental reason then fix it. | ||
395 | evas_damage_rectangle_add(obj->layer->evas, | ||
396 | 0, | ||
397 | 0, | ||
398 | obj->layer->evas->output.w, | ||
399 | obj->layer->evas->output.h); | ||
400 | } | ||
401 | } | ||
402 | _evas_map_calc_map_geometry(obj); | ||
403 | /* This is a bit heavy handed, but it fixes the case of same geometry, but | ||
404 | * changed colour or UV settings. */ | ||
405 | evas_object_change(obj); | ||
406 | } | ||
407 | |||
408 | EAPI Eina_Bool | ||
409 | evas_object_map_enable_get(const Evas_Object *obj) | ||
410 | { | ||
411 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
412 | return EINA_FALSE; | ||
413 | MAGIC_CHECK_END(); | ||
414 | return obj->cur.usemap; | ||
415 | } | ||
416 | |||
417 | |||
418 | EAPI void | ||
419 | evas_object_map_source_set(Evas_Object *obj, Evas_Object *src) | ||
420 | { | ||
421 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
422 | return; | ||
423 | MAGIC_CHECK_END(); | ||
424 | (void)src; /* method still needs to be implemented. */ | ||
425 | } | ||
426 | |||
427 | EAPI Evas_Object * | ||
428 | evas_object_map_source_get(const Evas_Object *obj) | ||
429 | { | ||
430 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
431 | return NULL; | ||
432 | MAGIC_CHECK_END(); | ||
433 | return NULL; | ||
434 | } | ||
435 | |||
436 | EAPI void | ||
437 | evas_object_map_set(Evas_Object *obj, const Evas_Map *map) | ||
438 | { | ||
439 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
440 | return; | ||
441 | MAGIC_CHECK_END(); | ||
442 | |||
443 | if (!map) | ||
444 | { | ||
445 | if (obj->cur.map) | ||
446 | { | ||
447 | if (obj->cur.map->surface) | ||
448 | { | ||
449 | obj->layer->evas->engine.func->image_map_surface_free | ||
450 | (obj->layer->evas->engine.data.output, | ||
451 | obj->cur.map->surface); | ||
452 | obj->cur.map->surface = NULL; | ||
453 | } | ||
454 | obj->prev.geometry = obj->cur.map->normal_geometry; | ||
455 | if (!obj->prev.map) | ||
456 | { | ||
457 | _evas_map_free(obj, obj->cur.map); | ||
458 | obj->cur.map = NULL; | ||
459 | evas_object_mapped_clip_across_mark(obj); | ||
460 | return; | ||
461 | } | ||
462 | _evas_map_free(obj, obj->cur.map); | ||
463 | obj->cur.map = NULL; | ||
464 | if (!obj->cur.usemap) _evas_map_calc_geom_change(obj); | ||
465 | else _evas_map_calc_map_geometry(obj); | ||
466 | if (obj->cur.usemap) | ||
467 | { | ||
468 | evas_object_mapped_clip_across_mark(obj); | ||
469 | //FIXME: Since the last frame is not updated when map is | ||
470 | //disabled, afterimage problem is happened in s/w | ||
471 | //rendering. Need to find out the fundamental reason | ||
472 | //then fix it. | ||
473 | evas_damage_rectangle_add(obj->layer->evas, | ||
474 | 0, | ||
475 | 0, | ||
476 | obj->layer->evas->output.w, | ||
477 | obj->layer->evas->output.h); | ||
478 | } | ||
479 | } | ||
480 | return; | ||
481 | } | ||
482 | |||
483 | if ((obj->cur.map) && (obj->cur.map->count == map->count)) | ||
484 | { | ||
485 | Evas_Map *omap = obj->cur.map; | ||
486 | obj->cur.map = _evas_map_new(map->count); | ||
487 | memcpy(obj->cur.map, omap, sizeof(Evas_Map) + (map->count * sizeof(Evas_Map_Point))); | ||
488 | _evas_map_copy(obj->cur.map, map); | ||
489 | if (obj->prev.map == omap) obj->prev.map = NULL; | ||
490 | free(omap); | ||
491 | } | ||
492 | else | ||
493 | { | ||
494 | if (obj->cur.map) evas_map_free(obj->cur.map); | ||
495 | obj->cur.map = _evas_map_dup(map); | ||
496 | if (obj->cur.usemap) | ||
497 | evas_object_mapped_clip_across_mark(obj); | ||
498 | } | ||
499 | _evas_map_calc_map_geometry(obj); | ||
500 | } | ||
501 | |||
502 | EAPI const Evas_Map * | ||
503 | evas_object_map_get(const Evas_Object *obj) | ||
504 | { | ||
505 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
506 | return NULL; | ||
507 | MAGIC_CHECK_END(); | ||
508 | |||
509 | return obj->cur.map; | ||
510 | } | ||
511 | |||
512 | EAPI Evas_Map * | ||
513 | evas_map_new(int count) | ||
514 | { | ||
515 | if (count != 4) | ||
516 | { | ||
517 | ERR("map point count (%i) != 4 is unsupported!", count); | ||
518 | return NULL; | ||
519 | } | ||
520 | |||
521 | return _evas_map_new(count); | ||
522 | } | ||
523 | |||
524 | EAPI void | ||
525 | evas_map_smooth_set(Evas_Map *m, Eina_Bool enabled) | ||
526 | { | ||
527 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
528 | return; | ||
529 | MAGIC_CHECK_END(); | ||
530 | |||
531 | m->smooth = enabled; | ||
532 | } | ||
533 | |||
534 | EAPI Eina_Bool | ||
535 | evas_map_smooth_get(const Evas_Map *m) | ||
536 | { | ||
537 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
538 | return EINA_FALSE; | ||
539 | MAGIC_CHECK_END(); | ||
540 | |||
541 | return m->smooth; | ||
542 | } | ||
543 | |||
544 | EAPI void | ||
545 | evas_map_alpha_set(Evas_Map *m, Eina_Bool enabled) | ||
546 | { | ||
547 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
548 | return; | ||
549 | MAGIC_CHECK_END(); | ||
550 | |||
551 | m->alpha = enabled; | ||
552 | } | ||
553 | |||
554 | EAPI Eina_Bool | ||
555 | evas_map_alpha_get(const Evas_Map *m) | ||
556 | { | ||
557 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
558 | return EINA_FALSE; | ||
559 | MAGIC_CHECK_END(); | ||
560 | |||
561 | return m->alpha; | ||
562 | } | ||
563 | |||
564 | EAPI Evas_Map * | ||
565 | evas_map_dup(const Evas_Map *m) | ||
566 | { | ||
567 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
568 | return NULL; | ||
569 | MAGIC_CHECK_END(); | ||
570 | |||
571 | return _evas_map_dup(m); | ||
572 | } | ||
573 | |||
574 | EAPI void | ||
575 | evas_map_free(Evas_Map *m) | ||
576 | { | ||
577 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
578 | return; | ||
579 | MAGIC_CHECK_END(); | ||
580 | |||
581 | _evas_map_free(NULL, m); | ||
582 | } | ||
583 | |||
584 | EAPI int | ||
585 | evas_map_count_get(const Evas_Map *m) | ||
586 | { | ||
587 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
588 | return -1; | ||
589 | MAGIC_CHECK_END(); | ||
590 | |||
591 | return m->count; | ||
592 | } | ||
593 | |||
594 | EAPI void | ||
595 | evas_map_point_coord_set(Evas_Map *m, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z) | ||
596 | { | ||
597 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
598 | return; | ||
599 | MAGIC_CHECK_END(); | ||
600 | |||
601 | Evas_Map_Point *p; | ||
602 | |||
603 | if (idx >= m->count) return; | ||
604 | p = m->points + idx; | ||
605 | p->x = p->px = x; | ||
606 | p->y = p->py = y; | ||
607 | p->z = z; | ||
608 | } | ||
609 | |||
610 | EAPI void | ||
611 | evas_map_point_coord_get(const Evas_Map *m, int idx, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z) | ||
612 | { | ||
613 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
614 | goto error; | ||
615 | MAGIC_CHECK_END(); | ||
616 | |||
617 | const Evas_Map_Point *p; | ||
618 | |||
619 | if (idx >= m->count) goto error; | ||
620 | p = m->points + idx; | ||
621 | if (x) *x = p->x; | ||
622 | if (y) *y = p->y; | ||
623 | if (z) *z = p->z; | ||
624 | return; | ||
625 | |||
626 | error: | ||
627 | if (x) *x = 0; | ||
628 | if (y) *y = 0; | ||
629 | if (z) *z = 0; | ||
630 | } | ||
631 | |||
632 | EAPI void | ||
633 | evas_map_point_image_uv_set(Evas_Map *m, int idx, double u, double v) | ||
634 | { | ||
635 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
636 | return; | ||
637 | MAGIC_CHECK_END(); | ||
638 | |||
639 | Evas_Map_Point *p; | ||
640 | |||
641 | if (idx >= m->count) return; | ||
642 | p = m->points + idx; | ||
643 | p->u = u; | ||
644 | p->v = v; | ||
645 | } | ||
646 | |||
647 | EAPI void | ||
648 | evas_map_point_image_uv_get(const Evas_Map *m, int idx, double *u, double *v) | ||
649 | { | ||
650 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
651 | goto error; | ||
652 | MAGIC_CHECK_END(); | ||
653 | |||
654 | const Evas_Map_Point *p; | ||
655 | |||
656 | if (idx >= m->count) goto error; | ||
657 | p = m->points + idx; | ||
658 | if (u) *u = p->u; | ||
659 | if (v) *v = p->v; | ||
660 | return; | ||
661 | |||
662 | error: | ||
663 | if (u) *u = 0.0; | ||
664 | if (v) *v = 0.0; | ||
665 | } | ||
666 | |||
667 | EAPI void | ||
668 | evas_map_point_color_set(Evas_Map *m, int idx, int r, int g, int b, int a) | ||
669 | { | ||
670 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
671 | return; | ||
672 | MAGIC_CHECK_END(); | ||
673 | |||
674 | Evas_Map_Point *p; | ||
675 | |||
676 | if (idx >= m->count) return; | ||
677 | p = m->points + idx; | ||
678 | p->r = r; | ||
679 | p->g = g; | ||
680 | p->b = b; | ||
681 | p->a = a; | ||
682 | } | ||
683 | |||
684 | EAPI void | ||
685 | evas_map_point_color_get(const Evas_Map *m, int idx, int *r, int *g, int *b, int *a) | ||
686 | { | ||
687 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
688 | return; | ||
689 | MAGIC_CHECK_END(); | ||
690 | |||
691 | const Evas_Map_Point *p; | ||
692 | |||
693 | if (idx >= m->count) return; | ||
694 | p = m->points + idx; | ||
695 | if (r) *r = p->r; | ||
696 | if (g) *g = p->g; | ||
697 | if (b) *b = p->b; | ||
698 | if (a) *a = p->a; | ||
699 | } | ||
700 | |||
701 | EAPI void | ||
702 | evas_map_util_points_populate_from_object_full(Evas_Map *m, const Evas_Object *obj, Evas_Coord z) | ||
703 | { | ||
704 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
705 | return; | ||
706 | MAGIC_CHECK_END(); | ||
707 | |||
708 | if (m->count != 4) | ||
709 | { | ||
710 | ERR("map has count=%d where 4 was expected.", m->count); | ||
711 | return; | ||
712 | } | ||
713 | _evas_map_util_points_populate(m, obj->cur.geometry.x, obj->cur.geometry.y, | ||
714 | obj->cur.geometry.w, obj->cur.geometry.h, z); | ||
715 | } | ||
716 | |||
717 | EAPI void | ||
718 | evas_map_util_points_populate_from_object(Evas_Map *m, const Evas_Object *obj) | ||
719 | { | ||
720 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
721 | return; | ||
722 | MAGIC_CHECK_END(); | ||
723 | |||
724 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
725 | return; | ||
726 | MAGIC_CHECK_END(); | ||
727 | |||
728 | if (m->count != 4) | ||
729 | { | ||
730 | ERR("map has count=%d where 4 was expected.", m->count); | ||
731 | return; | ||
732 | } | ||
733 | _evas_map_util_points_populate(m, obj->cur.geometry.x, obj->cur.geometry.y, | ||
734 | obj->cur.geometry.w, obj->cur.geometry.h, 0); | ||
735 | } | ||
736 | |||
737 | EAPI void | ||
738 | evas_map_util_points_populate_from_geometry(Evas_Map *m, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Evas_Coord z) | ||
739 | { | ||
740 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
741 | return; | ||
742 | MAGIC_CHECK_END(); | ||
743 | |||
744 | if (m->count != 4) | ||
745 | { | ||
746 | ERR("map has count=%d where 4 was expected.", m->count); | ||
747 | return; | ||
748 | } | ||
749 | _evas_map_util_points_populate(m, x, y, w, h, z); | ||
750 | } | ||
751 | |||
752 | EAPI void | ||
753 | evas_map_util_points_color_set(Evas_Map *m, int r, int g, int b, int a) | ||
754 | { | ||
755 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
756 | return; | ||
757 | MAGIC_CHECK_END(); | ||
758 | |||
759 | Evas_Map_Point *p, *p_end; | ||
760 | |||
761 | p = m->points; | ||
762 | p_end = p + m->count; | ||
763 | for (; p < p_end; p++) | ||
764 | { | ||
765 | p->r = r; | ||
766 | p->g = g; | ||
767 | p->b = b; | ||
768 | p->a = a; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | EAPI void | ||
773 | evas_map_util_rotate(Evas_Map *m, double degrees, Evas_Coord cx, Evas_Coord cy) | ||
774 | { | ||
775 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
776 | return; | ||
777 | MAGIC_CHECK_END(); | ||
778 | |||
779 | double r = (degrees * M_PI) / 180.0; | ||
780 | Evas_Map_Point *p, *p_end; | ||
781 | |||
782 | p = m->points; | ||
783 | p_end = p + m->count; | ||
784 | |||
785 | for (; p < p_end; p++) | ||
786 | { | ||
787 | double x, y, xx, yy; | ||
788 | |||
789 | x = p->x - cx; | ||
790 | y = p->y - cy; | ||
791 | |||
792 | xx = x * cos(r); | ||
793 | yy = x * sin(r); | ||
794 | x = xx - (y * sin(r)); | ||
795 | y = yy + (y * cos(r)); | ||
796 | |||
797 | p->px = p->x = x + cx; | ||
798 | p->py = p->y = y + cy; | ||
799 | } | ||
800 | } | ||
801 | |||
802 | EAPI void | ||
803 | evas_map_util_zoom(Evas_Map *m, double zoomx, double zoomy, Evas_Coord cx, Evas_Coord cy) | ||
804 | { | ||
805 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
806 | return; | ||
807 | MAGIC_CHECK_END(); | ||
808 | |||
809 | Evas_Map_Point *p, *p_end; | ||
810 | |||
811 | p = m->points; | ||
812 | p_end = p + m->count; | ||
813 | |||
814 | for (; p < p_end; p++) | ||
815 | { | ||
816 | double x, y; | ||
817 | |||
818 | x = p->x - cx; | ||
819 | y = p->y - cy; | ||
820 | |||
821 | x = (((double)x) * zoomx); | ||
822 | y = (((double)y) * zoomy); | ||
823 | |||
824 | p->px = p->x = x + cx; | ||
825 | p->py = p->y = y + cy; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | EAPI void | ||
830 | evas_map_util_3d_rotate(Evas_Map *m, double dx, double dy, double dz, | ||
831 | Evas_Coord cx, Evas_Coord cy, Evas_Coord cz) | ||
832 | { | ||
833 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
834 | return; | ||
835 | MAGIC_CHECK_END(); | ||
836 | |||
837 | double rz = (dz * M_PI) / 180.0; | ||
838 | double rx = (dx * M_PI) / 180.0; | ||
839 | double ry = (dy * M_PI) / 180.0; | ||
840 | Evas_Map_Point *p, *p_end; | ||
841 | |||
842 | p = m->points; | ||
843 | p_end = p + m->count; | ||
844 | |||
845 | for (; p < p_end; p++) | ||
846 | { | ||
847 | double x, y, z, xx, yy, zz; | ||
848 | |||
849 | x = p->x - cx; | ||
850 | y = p->y - cy; | ||
851 | z = p->z - cz; | ||
852 | |||
853 | if (rz != 0.0) | ||
854 | { | ||
855 | xx = x * cos(rz); | ||
856 | yy = x * sin(rz); | ||
857 | x = xx - (y * sin(rz)); | ||
858 | y = yy + (y * cos(rz)); | ||
859 | } | ||
860 | |||
861 | if (ry != 0.0) | ||
862 | { | ||
863 | xx = x * cos(ry); | ||
864 | zz = x * sin(ry); | ||
865 | x = xx - (z * sin(ry)); | ||
866 | z = zz + (z * cos(ry)); | ||
867 | } | ||
868 | |||
869 | if (rx != 0.0) | ||
870 | { | ||
871 | zz = z * cos(rx); | ||
872 | yy = z * sin(rx); | ||
873 | z = zz - (y * sin(rx)); | ||
874 | y = yy + (y * cos(rx)); | ||
875 | } | ||
876 | |||
877 | p->px = p->x = x + cx; | ||
878 | p->py = p->y = y + cy; | ||
879 | p->z = z + cz; | ||
880 | } | ||
881 | } | ||
882 | |||
883 | EAPI void | ||
884 | evas_map_util_3d_lighting(Evas_Map *m, | ||
885 | Evas_Coord lx, Evas_Coord ly, Evas_Coord lz, | ||
886 | int lr, int lg, int lb, int ar, int ag, int ab) | ||
887 | { | ||
888 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
889 | return; | ||
890 | MAGIC_CHECK_END(); | ||
891 | |||
892 | int i; | ||
893 | |||
894 | for (i = 0; i < m->count; i++) | ||
895 | { | ||
896 | double x, y, z; | ||
897 | double nx, ny, nz, x1, y1, z1, x2, y2, z2, ln, br; | ||
898 | int h, j, mr, mg, mb; | ||
899 | |||
900 | x = m->points[i].x; | ||
901 | y = m->points[i].y; | ||
902 | z = m->points[i].z; | ||
903 | // calc normal | ||
904 | h = (i - 1 + 4) % 4 + (i & ~0x3); // prev point | ||
905 | j = (i + 1) % 4 + (i & ~0x3); // next point | ||
906 | |||
907 | x1 = m->points[h].x - x; | ||
908 | y1 = m->points[h].y - y; | ||
909 | z1 = m->points[h].z - z; | ||
910 | |||
911 | x2 = m->points[j].x - x; | ||
912 | y2 = m->points[j].y - y; | ||
913 | z2 = m->points[j].z - z; | ||
914 | nx = (y1 * z2) - (z1 * y2); | ||
915 | ny = (z1 * x2) - (x1 * z2); | ||
916 | nz = (x1 * y2) - (y1 * x2); | ||
917 | |||
918 | ln = (nx * nx) + (ny * ny) + (nz * nz); | ||
919 | ln = sqrt(ln); | ||
920 | |||
921 | if (ln != 0.0) | ||
922 | { | ||
923 | nx /= ln; | ||
924 | ny /= ln; | ||
925 | nz /= ln; | ||
926 | } | ||
927 | |||
928 | // calc point -> light vector | ||
929 | x = lx - x; | ||
930 | y = ly - y; | ||
931 | z = lz - z; | ||
932 | |||
933 | ln = (x * x) + (y * y) + (z * z); | ||
934 | ln = sqrt(ln); | ||
935 | |||
936 | if (ln != 0.0) | ||
937 | { | ||
938 | x /= ln; | ||
939 | y /= ln; | ||
940 | z /= ln; | ||
941 | } | ||
942 | |||
943 | // brightness - tan (0.0 -> 1.0 brightness really) | ||
944 | br = (nx * x) + (ny * y) + (nz * z); | ||
945 | if (br < 0.0) br = 0.0; | ||
946 | |||
947 | mr = ar + ((lr - ar) * br); | ||
948 | mg = ag + ((lg - ag) * br); | ||
949 | mb = ab + ((lb - ab) * br); | ||
950 | if (m->points[i].a != 255) | ||
951 | { | ||
952 | mr = (mr * m->points[i].a) / 255; | ||
953 | mg = (mg * m->points[i].a) / 255; | ||
954 | mb = (mb * m->points[i].a) / 255; | ||
955 | } | ||
956 | m->points[i].r = (m->points[i].r * mr) / 255; | ||
957 | m->points[i].g = (m->points[i].g * mg) / 255; | ||
958 | m->points[i].b = (m->points[i].b * mb) / 255; | ||
959 | } | ||
960 | } | ||
961 | |||
962 | EAPI void | ||
963 | evas_map_util_3d_perspective(Evas_Map *m, | ||
964 | Evas_Coord px, Evas_Coord py, | ||
965 | Evas_Coord z0, Evas_Coord foc) | ||
966 | { | ||
967 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
968 | return; | ||
969 | MAGIC_CHECK_END(); | ||
970 | |||
971 | Evas_Map_Point *p, *p_end; | ||
972 | |||
973 | p = m->points; | ||
974 | p_end = p + m->count; | ||
975 | |||
976 | m->persp.px = px; | ||
977 | m->persp.py = py; | ||
978 | m->persp.z0 = z0; | ||
979 | m->persp.foc = foc; | ||
980 | |||
981 | if (foc <= 0) return; | ||
982 | |||
983 | for (; p < p_end; p++) | ||
984 | { | ||
985 | double x, y, zz; | ||
986 | |||
987 | x = p->x - px; | ||
988 | y = p->y - py; | ||
989 | |||
990 | zz = ((p->z - z0) + foc); | ||
991 | |||
992 | if (zz > 0) | ||
993 | { | ||
994 | x = (x * foc) / zz; | ||
995 | y = (y * foc) / zz; | ||
996 | } | ||
997 | |||
998 | p->x = px + x; | ||
999 | p->y = py + y; | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | EAPI Eina_Bool | ||
1004 | evas_map_util_clockwise_get(Evas_Map *m) | ||
1005 | { | ||
1006 | MAGIC_CHECK(m, Evas_Map, MAGIC_MAP); | ||
1007 | return EINA_FALSE; | ||
1008 | MAGIC_CHECK_END(); | ||
1009 | |||
1010 | int i, j, k, count; | ||
1011 | long long c; | ||
1012 | |||
1013 | if (m->count < 3) return EINA_FALSE; | ||
1014 | |||
1015 | count = 0; | ||
1016 | for (i = 0; i < m->count; i++) | ||
1017 | { | ||
1018 | j = (i + 1) % m->count; | ||
1019 | k = (i + 2) % m->count; | ||
1020 | c = | ||
1021 | ((m->points[j].x - m->points[i].x) * | ||
1022 | (m->points[k].y - m->points[j].y)) | ||
1023 | - | ||
1024 | ((m->points[j].y - m->points[i].y) * | ||
1025 | (m->points[k].x - m->points[j].x)); | ||
1026 | if (c < 0) count--; | ||
1027 | else if (c > 0) count++; | ||
1028 | } | ||
1029 | if (count > 0) return EINA_TRUE; | ||
1030 | return EINA_FALSE; | ||
1031 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_name.c b/libraries/evas/src/lib/canvas/evas_name.c new file mode 100644 index 0000000..c42f941 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_name.c | |||
@@ -0,0 +1,40 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | EAPI void | ||
5 | evas_object_name_set(Evas_Object *obj, const char *name) | ||
6 | { | ||
7 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
8 | return; | ||
9 | MAGIC_CHECK_END(); | ||
10 | if (obj->name) | ||
11 | { | ||
12 | eina_hash_del(obj->layer->evas->name_hash, obj->name, obj); | ||
13 | free(obj->name); | ||
14 | } | ||
15 | if (!name) obj->name = NULL; | ||
16 | else | ||
17 | { | ||
18 | obj->name = strdup(name); | ||
19 | eina_hash_add(obj->layer->evas->name_hash, obj->name, obj); | ||
20 | } | ||
21 | } | ||
22 | |||
23 | EAPI const char * | ||
24 | evas_object_name_get(const Evas_Object *obj) | ||
25 | { | ||
26 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
27 | return NULL; | ||
28 | MAGIC_CHECK_END(); | ||
29 | return obj->name; | ||
30 | } | ||
31 | |||
32 | EAPI Evas_Object * | ||
33 | evas_object_name_find(const Evas *e, const char *name) | ||
34 | { | ||
35 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
36 | return NULL; | ||
37 | MAGIC_CHECK_END(); | ||
38 | if (!name) return NULL; | ||
39 | return (Evas_Object *)eina_hash_find(e->name_hash, name); | ||
40 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_box.c b/libraries/evas/src/lib/canvas/evas_object_box.c new file mode 100644 index 0000000..ab2f222 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_box.c | |||
@@ -0,0 +1,2128 @@ | |||
1 | #include "evas_common.h" | ||
2 | |||
3 | #ifdef _WIN32_WCE | ||
4 | # undef remove | ||
5 | #endif | ||
6 | |||
7 | typedef struct _Evas_Object_Box_Iterator Evas_Object_Box_Iterator; | ||
8 | typedef struct _Evas_Object_Box_Accessor Evas_Object_Box_Accessor; | ||
9 | |||
10 | struct _Evas_Object_Box_Iterator | ||
11 | { | ||
12 | Eina_Iterator iterator; | ||
13 | |||
14 | Eina_Iterator *real_iterator; | ||
15 | const Evas_Object *box; | ||
16 | }; | ||
17 | |||
18 | struct _Evas_Object_Box_Accessor | ||
19 | { | ||
20 | Eina_Accessor accessor; | ||
21 | |||
22 | Eina_Accessor *real_accessor; | ||
23 | const Evas_Object *box; | ||
24 | }; | ||
25 | |||
26 | #define _evas_object_box_type "Evas_Object_Box" | ||
27 | #define SIG_CHILD_ADDED "child,added" | ||
28 | #define SIG_CHILD_REMOVED "child,removed" | ||
29 | |||
30 | static const Evas_Smart_Cb_Description _signals[] = | ||
31 | { | ||
32 | {SIG_CHILD_ADDED, ""}, | ||
33 | {SIG_CHILD_REMOVED, ""}, | ||
34 | {NULL, NULL} | ||
35 | }; | ||
36 | |||
37 | |||
38 | static void _sizing_eval(Evas_Object *obj); | ||
39 | |||
40 | #define EVAS_OBJECT_BOX_DATA_GET(o, ptr) \ | ||
41 | Evas_Object_Box_Data *ptr = evas_object_smart_data_get(o) | ||
42 | |||
43 | #define EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, ptr) \ | ||
44 | EVAS_OBJECT_BOX_DATA_GET(o, ptr); \ | ||
45 | if (!ptr) \ | ||
46 | { \ | ||
47 | CRIT("no widget data for object %p (%s)", \ | ||
48 | o, evas_object_type_get(o)); \ | ||
49 | fflush(stderr); \ | ||
50 | abort(); \ | ||
51 | return; \ | ||
52 | } | ||
53 | |||
54 | #define EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, ptr, val) \ | ||
55 | EVAS_OBJECT_BOX_DATA_GET(o, ptr); \ | ||
56 | if (!ptr) \ | ||
57 | { \ | ||
58 | CRIT("no widget data for object %p (%s)", \ | ||
59 | o, evas_object_type_get(o)); \ | ||
60 | fflush(stderr); \ | ||
61 | abort(); \ | ||
62 | return val; \ | ||
63 | } | ||
64 | |||
65 | EVAS_SMART_SUBCLASS_NEW(_evas_object_box_type, _evas_object_box, | ||
66 | Evas_Object_Box_Api, Evas_Smart_Class, | ||
67 | evas_object_smart_clipped_class_get, NULL) | ||
68 | |||
69 | static Eina_Bool | ||
70 | _evas_object_box_iterator_next(Evas_Object_Box_Iterator *it, void **data) | ||
71 | { | ||
72 | Evas_Object_Box_Option *opt; | ||
73 | |||
74 | if (!eina_iterator_next(it->real_iterator, (void **)&opt)) | ||
75 | return EINA_FALSE; | ||
76 | if (data) *data = opt->obj; | ||
77 | return EINA_TRUE; | ||
78 | } | ||
79 | |||
80 | static Evas_Object * | ||
81 | _evas_object_box_iterator_get_container(Evas_Object_Box_Iterator *it) | ||
82 | { | ||
83 | return (Evas_Object *)it->box; | ||
84 | } | ||
85 | |||
86 | static void | ||
87 | _evas_object_box_iterator_free(Evas_Object_Box_Iterator *it) | ||
88 | { | ||
89 | eina_iterator_free(it->real_iterator); | ||
90 | free(it); | ||
91 | } | ||
92 | |||
93 | static Eina_Bool | ||
94 | _evas_object_box_accessor_get_at(Evas_Object_Box_Accessor *it, unsigned int idx, void **data) | ||
95 | { | ||
96 | Evas_Object_Box_Option *opt = NULL; | ||
97 | |||
98 | if (!eina_accessor_data_get(it->real_accessor, idx, (void *)&opt)) | ||
99 | return EINA_FALSE; | ||
100 | if (data) *data = opt->obj; | ||
101 | return EINA_TRUE; | ||
102 | } | ||
103 | |||
104 | static Evas_Object * | ||
105 | _evas_object_box_accessor_get_container(Evas_Object_Box_Accessor *it) | ||
106 | { | ||
107 | return (Evas_Object *)it->box; | ||
108 | } | ||
109 | |||
110 | static void | ||
111 | _evas_object_box_accessor_free(Evas_Object_Box_Accessor *it) | ||
112 | { | ||
113 | eina_accessor_free(it->real_accessor); | ||
114 | free(it); | ||
115 | } | ||
116 | |||
117 | static void | ||
118 | _on_child_resize(void *data, Evas *evas __UNUSED__, Evas_Object *o __UNUSED__, void *einfo __UNUSED__) | ||
119 | { | ||
120 | Evas_Object *box = data; | ||
121 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(box, priv); | ||
122 | if (!priv->layouting) evas_object_smart_changed(box); | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | _on_child_del(void *data, Evas *evas __UNUSED__, Evas_Object *o, void *einfo __UNUSED__) | ||
127 | { | ||
128 | const Evas_Object_Box_Api *api; | ||
129 | Evas_Object *box = data; | ||
130 | |||
131 | EVAS_OBJECT_BOX_DATA_GET(box, priv); | ||
132 | api = priv->api; | ||
133 | |||
134 | if ((!api) || (!api->remove)) | ||
135 | { | ||
136 | ERR("no api->remove"); | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | if (!api->remove(box, priv, o)) | ||
141 | ERR("child removal failed"); | ||
142 | evas_object_smart_changed(box); | ||
143 | } | ||
144 | |||
145 | static void | ||
146 | _on_child_hints_changed(void *data, Evas *evas __UNUSED__, Evas_Object *o __UNUSED__, void *einfo __UNUSED__) | ||
147 | { | ||
148 | Evas_Object *box = data; | ||
149 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(box, priv); | ||
150 | if (!priv->layouting) evas_object_smart_changed(box); | ||
151 | } | ||
152 | |||
153 | static void | ||
154 | _on_hints_changed(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *o , void *einfo __UNUSED__) | ||
155 | { | ||
156 | _sizing_eval(o); | ||
157 | } | ||
158 | |||
159 | static Evas_Object_Box_Option * | ||
160 | _evas_object_box_option_new(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child) | ||
161 | { | ||
162 | Evas_Object_Box_Option *opt; | ||
163 | const Evas_Object_Box_Api *api; | ||
164 | |||
165 | api = priv->api; | ||
166 | if ((!api) || (!api->option_new)) | ||
167 | { | ||
168 | ERR("no api->option_new"); | ||
169 | return NULL; | ||
170 | } | ||
171 | |||
172 | opt = api->option_new(o, priv, child); | ||
173 | if (!opt) | ||
174 | { | ||
175 | ERR("option_new failed"); | ||
176 | return NULL; | ||
177 | } | ||
178 | |||
179 | return opt; | ||
180 | } | ||
181 | |||
182 | static void | ||
183 | _evas_object_box_child_callbacks_unregister(Evas_Object *obj) | ||
184 | { | ||
185 | evas_object_event_callback_del | ||
186 | (obj, EVAS_CALLBACK_RESIZE, _on_child_resize); | ||
187 | evas_object_event_callback_del | ||
188 | (obj, EVAS_CALLBACK_FREE, _on_child_del); | ||
189 | evas_object_event_callback_del | ||
190 | (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed); | ||
191 | } | ||
192 | |||
193 | static Evas_Object_Box_Option * | ||
194 | _evas_object_box_option_callbacks_register(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object_Box_Option *opt) | ||
195 | { | ||
196 | const Evas_Object_Box_Api *api; | ||
197 | Evas_Object *obj = opt->obj; | ||
198 | |||
199 | api = priv->api; | ||
200 | |||
201 | if ((!api) || (!api->option_free)) | ||
202 | { | ||
203 | WRN("api->option_free not set (may cause memory leaks, segfaults)"); | ||
204 | return NULL; | ||
205 | } | ||
206 | |||
207 | evas_object_event_callback_add | ||
208 | (obj, EVAS_CALLBACK_RESIZE, _on_child_resize, o); | ||
209 | evas_object_event_callback_add | ||
210 | (obj, EVAS_CALLBACK_FREE, _on_child_del, o); | ||
211 | evas_object_event_callback_add | ||
212 | (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o); | ||
213 | |||
214 | return opt; | ||
215 | } | ||
216 | |||
217 | static Evas_Object_Box_Option * | ||
218 | _evas_object_box_option_new_default(Evas_Object *o __UNUSED__, Evas_Object_Box_Data *priv __UNUSED__, Evas_Object *child) | ||
219 | { | ||
220 | Evas_Object_Box_Option *opt; | ||
221 | |||
222 | opt = (Evas_Object_Box_Option *)malloc(sizeof(*opt)); | ||
223 | if (!opt) | ||
224 | return NULL; | ||
225 | |||
226 | opt->obj = child; | ||
227 | |||
228 | return opt; | ||
229 | } | ||
230 | |||
231 | static void | ||
232 | _evas_object_box_option_free_default(Evas_Object *o __UNUSED__, Evas_Object_Box_Data *priv __UNUSED__, Evas_Object_Box_Option *opt) | ||
233 | { | ||
234 | free(opt); | ||
235 | } | ||
236 | |||
237 | static Evas_Object_Box_Option * | ||
238 | _evas_object_box_append_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child) | ||
239 | { | ||
240 | Evas_Object_Box_Option *opt; | ||
241 | |||
242 | opt = _evas_object_box_option_new(o, priv, child); | ||
243 | if (!opt) | ||
244 | return NULL; | ||
245 | |||
246 | priv->children = eina_list_append(priv->children, opt); | ||
247 | priv->children_changed = EINA_TRUE; | ||
248 | evas_object_smart_callback_call(o, SIG_CHILD_ADDED, opt); | ||
249 | |||
250 | return opt; | ||
251 | } | ||
252 | |||
253 | static Evas_Object_Box_Option * | ||
254 | _evas_object_box_prepend_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child) | ||
255 | { | ||
256 | Evas_Object_Box_Option *opt; | ||
257 | |||
258 | opt = _evas_object_box_option_new(o, priv, child); | ||
259 | if (!opt) | ||
260 | return NULL; | ||
261 | |||
262 | priv->children = eina_list_prepend(priv->children, opt); | ||
263 | priv->children_changed = EINA_TRUE; | ||
264 | evas_object_smart_callback_call(o, SIG_CHILD_ADDED, opt); | ||
265 | |||
266 | return opt; | ||
267 | } | ||
268 | |||
269 | static Evas_Object_Box_Option * | ||
270 | _evas_object_box_insert_before_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child, const Evas_Object *reference) | ||
271 | { | ||
272 | Eina_List *l; | ||
273 | Evas_Object_Box_Option *opt; | ||
274 | |||
275 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
276 | { | ||
277 | if (opt->obj == reference) | ||
278 | { | ||
279 | Evas_Object_Box_Option *new_opt; | ||
280 | |||
281 | new_opt = _evas_object_box_option_new(o, priv, child); | ||
282 | if (!new_opt) | ||
283 | return NULL; | ||
284 | |||
285 | priv->children = eina_list_prepend_relative | ||
286 | (priv->children, new_opt, opt); | ||
287 | priv->children_changed = EINA_TRUE; | ||
288 | evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt); | ||
289 | return new_opt; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | return NULL; | ||
294 | } | ||
295 | |||
296 | static Evas_Object_Box_Option * | ||
297 | _evas_object_box_insert_after_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child, const Evas_Object *reference) | ||
298 | { | ||
299 | Eina_List *l; | ||
300 | Evas_Object_Box_Option *opt; | ||
301 | |||
302 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
303 | { | ||
304 | if (opt->obj == reference) | ||
305 | { | ||
306 | Evas_Object_Box_Option *new_opt; | ||
307 | |||
308 | new_opt = _evas_object_box_option_new(o, priv, child); | ||
309 | if (!new_opt) | ||
310 | return NULL; | ||
311 | |||
312 | priv->children = eina_list_append_relative | ||
313 | (priv->children, new_opt, opt); | ||
314 | priv->children_changed = EINA_TRUE; | ||
315 | evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt); | ||
316 | return new_opt; | ||
317 | } | ||
318 | } | ||
319 | |||
320 | return NULL; | ||
321 | } | ||
322 | |||
323 | static Evas_Object_Box_Option * | ||
324 | _evas_object_box_insert_at_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child, unsigned int pos) | ||
325 | { | ||
326 | Eina_List *l; | ||
327 | unsigned int i; | ||
328 | |||
329 | if ((pos == 0) && (eina_list_count(priv->children) == 0)) | ||
330 | { | ||
331 | Evas_Object_Box_Option *new_opt; | ||
332 | |||
333 | new_opt = _evas_object_box_option_new(o, priv, child); | ||
334 | if (!new_opt) | ||
335 | return NULL; | ||
336 | |||
337 | priv->children = eina_list_prepend(priv->children, new_opt); | ||
338 | priv->children_changed = EINA_TRUE; | ||
339 | evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt); | ||
340 | return new_opt; | ||
341 | } | ||
342 | |||
343 | for (l = priv->children, i = 0; l; l = l->next, i++) | ||
344 | { | ||
345 | Evas_Object_Box_Option *opt = l->data; | ||
346 | |||
347 | if (i == pos) | ||
348 | { | ||
349 | Evas_Object_Box_Option *new_opt; | ||
350 | |||
351 | new_opt = _evas_object_box_option_new(o, priv, child); | ||
352 | if (!new_opt) | ||
353 | return NULL; | ||
354 | |||
355 | priv->children = eina_list_prepend_relative | ||
356 | (priv->children, new_opt, opt); | ||
357 | priv->children_changed = EINA_TRUE; | ||
358 | evas_object_smart_callback_call(o, SIG_CHILD_ADDED, new_opt); | ||
359 | return new_opt; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | return NULL; | ||
364 | } | ||
365 | |||
366 | static Evas_Object * | ||
367 | _evas_object_box_remove_default(Evas_Object *o, Evas_Object_Box_Data *priv, Evas_Object *child) | ||
368 | { | ||
369 | const Evas_Object_Box_Api *api; | ||
370 | Evas_Object_Box_Option *opt; | ||
371 | Eina_List *l; | ||
372 | |||
373 | api = priv->api; | ||
374 | |||
375 | if ((!api) || (!api->option_free)) | ||
376 | { | ||
377 | ERR("api->option_free not set (may cause memory leaks, segfaults)"); | ||
378 | return NULL; | ||
379 | } | ||
380 | |||
381 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
382 | { | ||
383 | Evas_Object *obj = opt->obj; | ||
384 | |||
385 | if (obj == child) | ||
386 | { | ||
387 | priv->children = eina_list_remove(priv->children, opt); | ||
388 | api->option_free(o, priv, opt); | ||
389 | priv->children_changed = EINA_TRUE; | ||
390 | evas_object_smart_callback_call(o, SIG_CHILD_REMOVED, obj); | ||
391 | |||
392 | return obj; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | return NULL; | ||
397 | } | ||
398 | |||
399 | static Evas_Object * | ||
400 | _evas_object_box_remove_at_default(Evas_Object *o, Evas_Object_Box_Data *priv, unsigned int pos) | ||
401 | { | ||
402 | const Evas_Object_Box_Api *api; | ||
403 | Eina_List *node; | ||
404 | Evas_Object_Box_Option *opt; | ||
405 | Evas_Object *obj; | ||
406 | |||
407 | api = priv->api; | ||
408 | |||
409 | if ((!api) || (!api->option_free)) | ||
410 | { | ||
411 | WRN("api->option_free not set (may cause memory leaks, segfaults)"); | ||
412 | return NULL; | ||
413 | } | ||
414 | |||
415 | node = eina_list_nth_list(priv->children, pos); | ||
416 | if (!node) | ||
417 | { | ||
418 | ERR("No item to be removed at position %d", pos); | ||
419 | return NULL; | ||
420 | } | ||
421 | |||
422 | opt = node->data; | ||
423 | obj = opt->obj; | ||
424 | |||
425 | priv->children = eina_list_remove_list(priv->children, node); | ||
426 | api->option_free(o, priv, opt); | ||
427 | priv->children_changed = EINA_TRUE; | ||
428 | evas_object_smart_callback_call(o, SIG_CHILD_REMOVED, obj); | ||
429 | return obj; | ||
430 | } | ||
431 | |||
432 | static void | ||
433 | _evas_object_box_smart_add(Evas_Object *o) | ||
434 | { | ||
435 | Evas_Object_Box_Data *priv; | ||
436 | |||
437 | priv = evas_object_smart_data_get(o); | ||
438 | if (!priv) | ||
439 | { | ||
440 | const Evas_Smart *smart; | ||
441 | const Evas_Smart_Class *sc; | ||
442 | |||
443 | priv = (Evas_Object_Box_Data *)calloc(1, sizeof(*priv)); | ||
444 | if (!priv) | ||
445 | { | ||
446 | ERR("Could not allocate object private data."); | ||
447 | return; | ||
448 | } | ||
449 | |||
450 | smart = evas_object_smart_smart_get(o); | ||
451 | sc = evas_smart_class_get(smart); | ||
452 | priv->api = (const Evas_Object_Box_Api *)sc; | ||
453 | |||
454 | evas_object_smart_data_set(o, priv); | ||
455 | } | ||
456 | _evas_object_box_parent_sc->add(o); | ||
457 | |||
458 | |||
459 | evas_object_event_callback_add | ||
460 | (o, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_hints_changed, o); | ||
461 | priv->children = NULL; | ||
462 | priv->align.h = 0.5; | ||
463 | priv->align.v = 0.5; | ||
464 | priv->pad.h = 0; | ||
465 | priv->pad.v = 0; | ||
466 | priv->layout.cb = evas_object_box_layout_horizontal; | ||
467 | priv->layout.data = NULL; | ||
468 | priv->layout.free_data = NULL; | ||
469 | } | ||
470 | |||
471 | static void | ||
472 | _evas_object_box_smart_del(Evas_Object *o) | ||
473 | { | ||
474 | const Evas_Object_Box_Api *api; | ||
475 | Eina_List *l; | ||
476 | |||
477 | EVAS_OBJECT_BOX_DATA_GET(o, priv); | ||
478 | |||
479 | api = priv->api; | ||
480 | if ((!api) || (!api->option_free)) | ||
481 | { | ||
482 | WRN("api->option_free not set (may cause memory leaks, segfaults)"); | ||
483 | return; | ||
484 | } | ||
485 | |||
486 | l = priv->children; | ||
487 | while (l) | ||
488 | { | ||
489 | Evas_Object_Box_Option *opt = l->data; | ||
490 | |||
491 | _evas_object_box_child_callbacks_unregister(opt->obj); | ||
492 | api->option_free(o, priv, opt); | ||
493 | l = eina_list_remove_list(l, l); | ||
494 | } | ||
495 | |||
496 | if (priv->layout.data && priv->layout.free_data) | ||
497 | priv->layout.free_data(priv->layout.data); | ||
498 | |||
499 | _evas_object_box_parent_sc->del(o); | ||
500 | } | ||
501 | |||
502 | static void | ||
503 | _evas_object_box_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h) | ||
504 | { | ||
505 | Evas_Coord ow, oh; | ||
506 | evas_object_geometry_get(o, NULL, NULL, &ow, &oh); | ||
507 | if ((ow == w) && (oh == h)) return; | ||
508 | evas_object_smart_changed(o); | ||
509 | } | ||
510 | |||
511 | static void | ||
512 | _evas_object_box_smart_calculate(Evas_Object *o) | ||
513 | { | ||
514 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv); | ||
515 | if (priv->layout.cb) | ||
516 | { | ||
517 | priv->layouting = 1; | ||
518 | priv->layout.cb(o, priv, priv->layout.data); | ||
519 | priv->layouting = 0; | ||
520 | priv->children_changed = EINA_FALSE; | ||
521 | } | ||
522 | else | ||
523 | ERR("No layout function set for %p box.", o); | ||
524 | } | ||
525 | |||
526 | static void | ||
527 | _evas_object_box_smart_set_user(Evas_Object_Box_Api *api) | ||
528 | { | ||
529 | api->base.add = _evas_object_box_smart_add; | ||
530 | api->base.del = _evas_object_box_smart_del; | ||
531 | api->base.resize = _evas_object_box_smart_resize; | ||
532 | api->base.calculate = _evas_object_box_smart_calculate; | ||
533 | api->base.callbacks = _signals; | ||
534 | |||
535 | api->append = _evas_object_box_append_default; | ||
536 | api->prepend = _evas_object_box_prepend_default; | ||
537 | api->insert_before = _evas_object_box_insert_before_default; | ||
538 | api->insert_after = _evas_object_box_insert_after_default; | ||
539 | api->insert_at = _evas_object_box_insert_at_default; | ||
540 | api->remove = _evas_object_box_remove_default; | ||
541 | api->remove_at = _evas_object_box_remove_at_default; | ||
542 | api->option_new = _evas_object_box_option_new_default; | ||
543 | api->option_free = _evas_object_box_option_free_default; | ||
544 | } | ||
545 | |||
546 | EAPI Evas_Object * | ||
547 | evas_object_box_add(Evas *evas) | ||
548 | { | ||
549 | return evas_object_smart_add(evas, _evas_object_box_smart_class_new()); | ||
550 | } | ||
551 | |||
552 | EAPI Evas_Object * | ||
553 | evas_object_box_add_to(Evas_Object *parent) | ||
554 | { | ||
555 | Evas *evas; | ||
556 | Evas_Object *o; | ||
557 | |||
558 | evas = evas_object_evas_get(parent); | ||
559 | o = evas_object_box_add(evas); | ||
560 | evas_object_smart_member_add(o, parent); | ||
561 | return o; | ||
562 | } | ||
563 | |||
564 | EAPI void | ||
565 | evas_object_box_smart_set(Evas_Object_Box_Api *api) | ||
566 | { | ||
567 | if (!api) | ||
568 | return; | ||
569 | _evas_object_box_smart_set(api); | ||
570 | } | ||
571 | |||
572 | EAPI const Evas_Object_Box_Api * | ||
573 | evas_object_box_smart_class_get(void) | ||
574 | { | ||
575 | static Evas_Object_Box_Api _sc = | ||
576 | EVAS_OBJECT_BOX_API_INIT_NAME_VERSION(_evas_object_box_type); | ||
577 | static const Evas_Object_Box_Api *class = NULL; | ||
578 | |||
579 | if (class) | ||
580 | return class; | ||
581 | |||
582 | evas_object_box_smart_set(&_sc); | ||
583 | class = &_sc; | ||
584 | |||
585 | return class; | ||
586 | } | ||
587 | |||
588 | EAPI void | ||
589 | evas_object_box_layout_set(Evas_Object *o, Evas_Object_Box_Layout cb, const void *data, void (*free_data)(void *data)) | ||
590 | { | ||
591 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv); | ||
592 | |||
593 | if ((priv->layout.cb == cb) && (priv->layout.data == data) && | ||
594 | (priv->layout.free_data == free_data)) | ||
595 | return; | ||
596 | |||
597 | if (priv->layout.data && priv->layout.free_data) | ||
598 | priv->layout.free_data(priv->layout.data); | ||
599 | |||
600 | priv->layout.cb = cb; | ||
601 | priv->layout.data = (void *)data; | ||
602 | priv->layout.free_data = free_data; | ||
603 | evas_object_smart_changed(o); | ||
604 | } | ||
605 | |||
606 | static void | ||
607 | _fixed_point_divide_and_decompose_integer(int dividend, int divisor, int *int_part, int *frac_part) | ||
608 | { | ||
609 | int quotient = (long long)(dividend << 16) / divisor; | ||
610 | *frac_part = quotient & 0xffff; | ||
611 | *int_part = quotient >> 16; | ||
612 | } | ||
613 | |||
614 | static void | ||
615 | _layout_dimension_change_min_max_cell_bound(int dim, int *new_dim, int min_d, int max_d, int cell_sz) | ||
616 | { | ||
617 | if (dim > cell_sz) | ||
618 | { | ||
619 | if ((min_d != 0) && (cell_sz < min_d)) | ||
620 | *new_dim = min_d; | ||
621 | else | ||
622 | *new_dim = cell_sz; | ||
623 | } | ||
624 | else | ||
625 | { | ||
626 | if ((max_d != -1) && (cell_sz > max_d)) | ||
627 | *new_dim = max_d; | ||
628 | else | ||
629 | *new_dim = cell_sz; | ||
630 | } | ||
631 | } | ||
632 | |||
633 | static void | ||
634 | _layout_set_offset_and_expand_dimension_space_max_bounded(int dim, int *new_dim, int space_sz, int max_dim, int *offset, double align, int pad_before, int pad_after) | ||
635 | { | ||
636 | if (align >= 0.0) | ||
637 | { | ||
638 | *new_dim = dim; | ||
639 | *offset = (space_sz - (dim + pad_before + pad_after)) * align | ||
640 | + pad_before; | ||
641 | } | ||
642 | else | ||
643 | { | ||
644 | if ((max_dim != -1) && (space_sz > max_dim)) | ||
645 | { | ||
646 | *new_dim = max_dim; | ||
647 | *offset = (space_sz - (max_dim + pad_before + pad_after)) * 0.5 | ||
648 | + pad_before; | ||
649 | } | ||
650 | else | ||
651 | { | ||
652 | *new_dim = space_sz; | ||
653 | *offset = 0; | ||
654 | } | ||
655 | } | ||
656 | } | ||
657 | |||
658 | static void | ||
659 | _layout_set_offset_and_change_dimension_min_max_cell_bounded(int dim, int *new_dim, int min_dim, int max_dim, int cell_sz, int *offset, double align, int pad_before, int pad_after) | ||
660 | { | ||
661 | if (align >= 0.0) | ||
662 | { | ||
663 | *new_dim = dim; | ||
664 | *offset = | ||
665 | (cell_sz - (dim + pad_before + pad_after)) * align + pad_before; | ||
666 | } | ||
667 | else | ||
668 | { | ||
669 | *offset = pad_before; | ||
670 | _layout_dimension_change_min_max_cell_bound | ||
671 | (dim, new_dim, min_dim, max_dim, cell_sz - pad_before - pad_after); | ||
672 | } | ||
673 | } | ||
674 | |||
675 | static void | ||
676 | _sizing_eval(Evas_Object *obj) | ||
677 | { | ||
678 | Evas_Coord minw, minh, maxw, maxh; | ||
679 | Evas_Coord w, h; | ||
680 | |||
681 | evas_object_size_hint_min_get(obj, &minw, &minh); | ||
682 | evas_object_size_hint_max_get(obj, &maxw, &maxh); | ||
683 | evas_object_geometry_get(obj, NULL, NULL, &w, &h); | ||
684 | |||
685 | if (w < minw) w = minw; | ||
686 | if (h < minh) h = minh; | ||
687 | if ((maxw >= 0) && (w > maxw)) w = maxw; | ||
688 | if ((maxh >= 0) && (h > maxh)) h = maxh; | ||
689 | |||
690 | evas_object_resize(obj, w, h); | ||
691 | } | ||
692 | |||
693 | static int | ||
694 | _evas_object_box_layout_horizontal_weight_apply(Evas_Object_Box_Data *priv, Evas_Object_Box_Option **objects, int n_objects, int remaining, int weight_total) | ||
695 | { | ||
696 | int rem_diff = 0; | ||
697 | int i; | ||
698 | |||
699 | for (i = 0; i < n_objects; i++) | ||
700 | { | ||
701 | Evas_Object_Box_Option *opt = objects[i]; | ||
702 | Evas_Object *o = opt->obj; | ||
703 | int h; | ||
704 | |||
705 | evas_object_geometry_get(o, NULL, NULL, NULL, &h); | ||
706 | |||
707 | if (remaining <= 0) | ||
708 | { | ||
709 | int min_w; | ||
710 | |||
711 | evas_object_size_hint_min_get(o, &min_w, NULL); | ||
712 | evas_object_resize(o, min_w, h); | ||
713 | } | ||
714 | else | ||
715 | { | ||
716 | double normal_weight, weight_x; | ||
717 | int target_size; | ||
718 | int max_w; | ||
719 | |||
720 | evas_object_size_hint_weight_get(o, &weight_x, NULL); | ||
721 | normal_weight = weight_x / weight_total; | ||
722 | target_size = (int)((double)remaining * normal_weight); | ||
723 | |||
724 | evas_object_size_hint_max_get(o, &max_w, NULL); | ||
725 | if ((max_w != -1) && (target_size > max_w)) | ||
726 | { | ||
727 | evas_object_resize(o, max_w, h); | ||
728 | rem_diff += max_w; | ||
729 | objects[i] = objects[n_objects - 1]; | ||
730 | weight_total -= weight_x; | ||
731 | n_objects--; | ||
732 | return _evas_object_box_layout_horizontal_weight_apply | ||
733 | (priv, objects, n_objects, remaining - rem_diff, | ||
734 | weight_total); | ||
735 | } | ||
736 | else | ||
737 | { | ||
738 | evas_object_resize(o, target_size, h); | ||
739 | rem_diff += target_size; | ||
740 | } | ||
741 | } | ||
742 | } | ||
743 | |||
744 | return remaining - rem_diff; | ||
745 | } | ||
746 | |||
747 | EAPI void | ||
748 | evas_object_box_layout_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
749 | { | ||
750 | int pad_inc = 0, sub_pixel = 0; | ||
751 | int req_w, global_pad, remaining, top_h = 0; | ||
752 | double weight_total = 0.0; | ||
753 | int weight_use = 0; | ||
754 | int x, y, w, h; | ||
755 | int n_children; | ||
756 | Evas_Object_Box_Option *opt; | ||
757 | Evas_Object_Box_Option **objects; | ||
758 | Eina_List *l; | ||
759 | |||
760 | n_children = eina_list_count(priv->children); | ||
761 | if (!n_children) | ||
762 | return; | ||
763 | |||
764 | objects = (Evas_Object_Box_Option **)alloca(sizeof(Evas_Object_Box_Option *) * n_children); | ||
765 | if (!objects) | ||
766 | return; | ||
767 | |||
768 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
769 | global_pad = priv->pad.h; | ||
770 | req_w = global_pad * (n_children - 1); | ||
771 | |||
772 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
773 | { | ||
774 | int padding_l, padding_r; | ||
775 | double weight_x; | ||
776 | |||
777 | _sizing_eval(opt->obj); | ||
778 | evas_object_size_hint_weight_get(opt->obj, &weight_x, NULL); | ||
779 | evas_object_size_hint_padding_get | ||
780 | (opt->obj, &padding_l, &padding_r, NULL, NULL); | ||
781 | req_w += padding_l + padding_r; | ||
782 | |||
783 | if (!weight_x) | ||
784 | { | ||
785 | int child_w; | ||
786 | |||
787 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, NULL); | ||
788 | req_w += child_w; | ||
789 | } | ||
790 | else | ||
791 | { | ||
792 | objects[weight_use] = opt; | ||
793 | weight_use++; | ||
794 | weight_total += weight_x; | ||
795 | } | ||
796 | } | ||
797 | |||
798 | remaining = w - req_w; | ||
799 | |||
800 | if (weight_use) | ||
801 | remaining = _evas_object_box_layout_horizontal_weight_apply | ||
802 | (priv, objects, weight_use, remaining, weight_total); | ||
803 | |||
804 | if (priv->align.h >= 0.0) | ||
805 | x += remaining * priv->align.h; | ||
806 | else if (n_children == 1) | ||
807 | x += remaining / 2; | ||
808 | else | ||
809 | { /* justified */ | ||
810 | _fixed_point_divide_and_decompose_integer | ||
811 | (remaining, n_children - 1, &global_pad, &pad_inc); | ||
812 | global_pad += priv->pad.h; | ||
813 | } | ||
814 | |||
815 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
816 | { | ||
817 | int child_w, child_h, max_h, new_h, off_x, off_y; | ||
818 | int padding_l, padding_r, padding_t, padding_b; | ||
819 | double align_y; | ||
820 | |||
821 | evas_object_size_hint_align_get(opt->obj, NULL, &align_y); | ||
822 | evas_object_size_hint_padding_get | ||
823 | (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b); | ||
824 | evas_object_size_hint_max_get(opt->obj, NULL, &max_h); | ||
825 | |||
826 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h); | ||
827 | |||
828 | off_x = padding_l; | ||
829 | new_h = child_h; | ||
830 | if (new_h > top_h) top_h = new_h; | ||
831 | |||
832 | _layout_set_offset_and_expand_dimension_space_max_bounded | ||
833 | (child_h, &new_h, h, max_h, &off_y, align_y, padding_t, padding_b); | ||
834 | |||
835 | if (new_h != child_h) | ||
836 | evas_object_resize(opt->obj, child_w, new_h); | ||
837 | evas_object_move(opt->obj, x + off_x, y + off_y); | ||
838 | |||
839 | x += child_w + padding_l + padding_r + global_pad; | ||
840 | sub_pixel += pad_inc; | ||
841 | if (sub_pixel >= 1 << 16) | ||
842 | { | ||
843 | x++; | ||
844 | sub_pixel -= 1 << 16; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | evas_object_size_hint_min_set(o, req_w, top_h); | ||
849 | } | ||
850 | |||
851 | static int | ||
852 | _evas_object_box_layout_vertical_weight_apply(Evas_Object_Box_Data *priv, Evas_Object_Box_Option **objects, int n_objects, int remaining, int weight_total) | ||
853 | { | ||
854 | int rem_diff = 0; | ||
855 | int i; | ||
856 | |||
857 | for (i = 0; i < n_objects; i++) | ||
858 | { | ||
859 | Evas_Object_Box_Option *opt = objects[i]; | ||
860 | Evas_Object *o = opt->obj; | ||
861 | int w; | ||
862 | |||
863 | evas_object_geometry_get(o, NULL, NULL, &w, NULL); | ||
864 | |||
865 | if (remaining <= 0) | ||
866 | { | ||
867 | int min_h; | ||
868 | |||
869 | evas_object_size_hint_min_get(o, NULL, &min_h); | ||
870 | evas_object_resize(o, w, min_h); | ||
871 | } | ||
872 | else | ||
873 | { | ||
874 | double normal_weight, weight_y; | ||
875 | int target_size; | ||
876 | int max_h; | ||
877 | |||
878 | evas_object_size_hint_weight_get(o, NULL, &weight_y); | ||
879 | normal_weight = weight_y / weight_total; | ||
880 | target_size = (int)((double)remaining * normal_weight); | ||
881 | |||
882 | evas_object_size_hint_max_get(o, NULL, &max_h); | ||
883 | if ((max_h != -1) && (target_size > max_h)) | ||
884 | { | ||
885 | evas_object_resize(o, w, max_h); | ||
886 | rem_diff += max_h; | ||
887 | objects[i] = objects[n_objects - 1]; | ||
888 | weight_total -= weight_y; | ||
889 | n_objects--; | ||
890 | return _evas_object_box_layout_vertical_weight_apply | ||
891 | (priv, objects, n_objects, remaining - rem_diff, | ||
892 | weight_total); | ||
893 | } | ||
894 | else | ||
895 | { | ||
896 | evas_object_resize(o, w, target_size); | ||
897 | rem_diff += target_size; | ||
898 | } | ||
899 | } | ||
900 | } | ||
901 | |||
902 | return remaining - rem_diff; | ||
903 | } | ||
904 | |||
905 | EAPI void | ||
906 | evas_object_box_layout_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
907 | { | ||
908 | int pad_inc = 0, sub_pixel = 0; | ||
909 | int req_h, global_pad, remaining, top_w = 0; | ||
910 | double weight_total = 0.0; | ||
911 | int weight_use = 0; | ||
912 | int x, y, w, h; | ||
913 | int n_children; | ||
914 | Evas_Object_Box_Option *opt; | ||
915 | Evas_Object_Box_Option **objects; | ||
916 | Eina_List *l; | ||
917 | |||
918 | n_children = eina_list_count(priv->children); | ||
919 | if (!n_children) | ||
920 | return; | ||
921 | |||
922 | objects = (Evas_Object_Box_Option **)alloca(sizeof(Evas_Object_Box_Option *) * n_children); | ||
923 | if (!objects) | ||
924 | return; | ||
925 | |||
926 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
927 | global_pad = priv->pad.v; | ||
928 | req_h = global_pad * (n_children - 1); | ||
929 | |||
930 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
931 | { | ||
932 | int padding_t, padding_b; | ||
933 | double weight_y; | ||
934 | |||
935 | _sizing_eval(opt->obj); | ||
936 | evas_object_size_hint_weight_get(opt->obj, NULL, &weight_y); | ||
937 | evas_object_size_hint_padding_get | ||
938 | (opt->obj, NULL, NULL, &padding_t, &padding_b); | ||
939 | req_h += padding_t + padding_b; | ||
940 | |||
941 | if (!weight_y) | ||
942 | { | ||
943 | int child_h; | ||
944 | |||
945 | evas_object_geometry_get(opt->obj, NULL, NULL, NULL, &child_h); | ||
946 | req_h += child_h; | ||
947 | } | ||
948 | else | ||
949 | { | ||
950 | objects[weight_use] = opt; | ||
951 | weight_use++; | ||
952 | weight_total += weight_y; | ||
953 | } | ||
954 | } | ||
955 | |||
956 | remaining = h - req_h; | ||
957 | |||
958 | if (weight_use) | ||
959 | remaining = _evas_object_box_layout_vertical_weight_apply | ||
960 | (priv, objects, weight_use, remaining, weight_total); | ||
961 | |||
962 | if (priv->align.v >= 0.0) | ||
963 | y += remaining * priv->align.v; | ||
964 | else if (n_children == 1) | ||
965 | y += remaining / 2; | ||
966 | else | ||
967 | { /* justified */ | ||
968 | _fixed_point_divide_and_decompose_integer | ||
969 | (remaining, n_children - 1, &global_pad, &pad_inc); | ||
970 | global_pad += priv->pad.v; | ||
971 | } | ||
972 | |||
973 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
974 | { | ||
975 | int child_w, child_h, max_w, new_w, off_x, off_y; | ||
976 | int padding_l, padding_r, padding_t, padding_b; | ||
977 | double align_x; | ||
978 | |||
979 | evas_object_size_hint_align_get(opt->obj, &align_x, NULL); | ||
980 | evas_object_size_hint_padding_get | ||
981 | (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b); | ||
982 | evas_object_size_hint_max_get(opt->obj, &max_w, NULL); | ||
983 | |||
984 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h); | ||
985 | |||
986 | off_y = padding_t; | ||
987 | new_w = child_w; | ||
988 | |||
989 | _layout_set_offset_and_expand_dimension_space_max_bounded | ||
990 | (child_w, &new_w, w, max_w, &off_x, align_x, padding_l, padding_r); | ||
991 | |||
992 | if (new_w > top_w) top_w = new_w; | ||
993 | |||
994 | if (new_w != child_w) | ||
995 | evas_object_resize(opt->obj, new_w, child_h); | ||
996 | evas_object_move(opt->obj, x + off_x, y + off_y); | ||
997 | |||
998 | y += child_h + padding_t + padding_b + global_pad; | ||
999 | sub_pixel += pad_inc; | ||
1000 | if (sub_pixel >= 1 << 16) | ||
1001 | { | ||
1002 | y++; | ||
1003 | sub_pixel -= 1 << 16; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | evas_object_size_hint_min_set(o, top_w, req_h); | ||
1008 | } | ||
1009 | |||
1010 | EAPI void | ||
1011 | evas_object_box_layout_homogeneous_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
1012 | { | ||
1013 | int cell_sz, share, inc; | ||
1014 | int sub_pixel = 0; | ||
1015 | int x, y, w, h; | ||
1016 | int n_children; | ||
1017 | Evas_Object_Box_Option *opt; | ||
1018 | Eina_List *l; | ||
1019 | |||
1020 | n_children = eina_list_count(priv->children); | ||
1021 | if (!n_children) | ||
1022 | return; | ||
1023 | |||
1024 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
1025 | |||
1026 | share = w - priv->pad.h * (n_children - 1); | ||
1027 | _fixed_point_divide_and_decompose_integer | ||
1028 | (share, n_children, &cell_sz, &inc); | ||
1029 | |||
1030 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1031 | { | ||
1032 | int child_w, child_h, max_h, min_w, max_w, new_w, new_h, off_x, off_y; | ||
1033 | int padding_l, padding_r, padding_t, padding_b; | ||
1034 | double align_x, align_y; | ||
1035 | |||
1036 | evas_object_size_hint_align_get(opt->obj, &align_x, &align_y); | ||
1037 | evas_object_size_hint_padding_get | ||
1038 | (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b); | ||
1039 | evas_object_size_hint_max_get(opt->obj, &max_w, &max_h); | ||
1040 | evas_object_size_hint_min_get(opt->obj, &min_w, NULL); | ||
1041 | |||
1042 | _sizing_eval(opt->obj); | ||
1043 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h); | ||
1044 | |||
1045 | new_w = child_w; | ||
1046 | new_h = child_h; | ||
1047 | |||
1048 | _layout_set_offset_and_expand_dimension_space_max_bounded | ||
1049 | (child_h, &new_h, h, max_h, &off_y, align_y, padding_t, padding_b); | ||
1050 | |||
1051 | _layout_set_offset_and_change_dimension_min_max_cell_bounded | ||
1052 | (child_w, &new_w, min_w, max_w, cell_sz, &off_x, align_x, | ||
1053 | padding_l, padding_r); | ||
1054 | |||
1055 | if ((new_w != child_w) || (new_h != child_h)) | ||
1056 | evas_object_resize(opt->obj, new_w, new_h); | ||
1057 | evas_object_move(opt->obj, x + off_x, y + off_y); | ||
1058 | |||
1059 | x += cell_sz + priv->pad.h; | ||
1060 | sub_pixel += inc; | ||
1061 | if (sub_pixel >= 1 << 16) | ||
1062 | { | ||
1063 | x++; | ||
1064 | sub_pixel -= 1 << 16; | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | evas_object_size_hint_min_set(o, w, h); | ||
1069 | } | ||
1070 | |||
1071 | EAPI void | ||
1072 | evas_object_box_layout_homogeneous_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
1073 | { | ||
1074 | int cell_sz, share, inc; | ||
1075 | int sub_pixel = 0; | ||
1076 | int x, y, w, h; | ||
1077 | int n_children; | ||
1078 | Evas_Object_Box_Option *opt; | ||
1079 | Eina_List *l; | ||
1080 | |||
1081 | n_children = eina_list_count(priv->children); | ||
1082 | if (!n_children) | ||
1083 | return; | ||
1084 | |||
1085 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
1086 | |||
1087 | share = h - priv->pad.v * (n_children - 1); | ||
1088 | _fixed_point_divide_and_decompose_integer | ||
1089 | (share, n_children, &cell_sz, &inc); | ||
1090 | |||
1091 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1092 | { | ||
1093 | int child_w, child_h, max_w, min_h, max_h, new_w, new_h, off_x, off_y; | ||
1094 | int padding_l, padding_r, padding_t, padding_b; | ||
1095 | double align_x, align_y; | ||
1096 | |||
1097 | evas_object_size_hint_align_get(opt->obj, &align_x, &align_y); | ||
1098 | evas_object_size_hint_padding_get | ||
1099 | (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b); | ||
1100 | evas_object_size_hint_max_get(opt->obj, &max_w, &max_h); | ||
1101 | evas_object_size_hint_min_get(opt->obj, NULL, &min_h); | ||
1102 | |||
1103 | _sizing_eval(opt->obj); | ||
1104 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h); | ||
1105 | new_w = child_w; | ||
1106 | new_h = child_h; | ||
1107 | |||
1108 | _layout_set_offset_and_expand_dimension_space_max_bounded | ||
1109 | (child_w, &new_w, w, max_w, &off_x, align_x, padding_l, padding_r); | ||
1110 | |||
1111 | _layout_set_offset_and_change_dimension_min_max_cell_bounded | ||
1112 | (child_h, &new_h, min_h, max_h, cell_sz, &off_y, align_y, | ||
1113 | padding_t, padding_b); | ||
1114 | |||
1115 | if ((new_w != child_w) || (new_h != child_h)) | ||
1116 | evas_object_resize(opt->obj, new_w, new_h); | ||
1117 | evas_object_move(opt->obj, x + off_x, y + off_y); | ||
1118 | |||
1119 | y += cell_sz + priv->pad.v; | ||
1120 | sub_pixel += inc; | ||
1121 | if (sub_pixel >= 1 << 16) | ||
1122 | { | ||
1123 | y++; | ||
1124 | sub_pixel -= 1 << 16; | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | evas_object_size_hint_min_set(o, w, h); | ||
1129 | } | ||
1130 | |||
1131 | EAPI void | ||
1132 | evas_object_box_layout_homogeneous_max_size_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
1133 | { | ||
1134 | int remaining, global_pad, pad_inc = 0, sub_pixel = 0; | ||
1135 | int cell_sz = 0; | ||
1136 | int x, y, w, h; | ||
1137 | int top_h = 0; | ||
1138 | int n_children; | ||
1139 | Evas_Object_Box_Option *opt; | ||
1140 | Eina_List *l; | ||
1141 | |||
1142 | n_children = eina_list_count(priv->children); | ||
1143 | if (!n_children) | ||
1144 | return; | ||
1145 | |||
1146 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
1147 | |||
1148 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1149 | { | ||
1150 | int child_w, padding_l, padding_r; | ||
1151 | |||
1152 | _sizing_eval(opt->obj); | ||
1153 | evas_object_size_hint_padding_get | ||
1154 | (opt->obj, &padding_l, &padding_r, NULL, NULL); | ||
1155 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, NULL); | ||
1156 | if (child_w + padding_l + padding_r > cell_sz) | ||
1157 | cell_sz = child_w + padding_l + padding_r; | ||
1158 | } | ||
1159 | |||
1160 | global_pad = priv->pad.h; | ||
1161 | remaining = w - n_children * cell_sz - global_pad * (n_children - 1); | ||
1162 | |||
1163 | if (priv->align.h >= 0.0) | ||
1164 | x += remaining * priv->align.h; | ||
1165 | else if (n_children == 1) | ||
1166 | x += remaining / 2; | ||
1167 | else | ||
1168 | { /* justified */ | ||
1169 | _fixed_point_divide_and_decompose_integer | ||
1170 | (remaining, n_children - 1, &global_pad, &pad_inc); | ||
1171 | global_pad += priv->pad.h; | ||
1172 | } | ||
1173 | |||
1174 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1175 | { | ||
1176 | int child_w, child_h, min_w, max_w, max_h, new_w, new_h, off_x, off_y; | ||
1177 | int padding_l, padding_r, padding_t, padding_b; | ||
1178 | double align_x, align_y; | ||
1179 | |||
1180 | evas_object_size_hint_align_get(opt->obj, &align_x, &align_y); | ||
1181 | evas_object_size_hint_padding_get | ||
1182 | (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b); | ||
1183 | evas_object_size_hint_max_get(opt->obj, &max_w, &max_h); | ||
1184 | evas_object_size_hint_min_get(opt->obj, &min_w, NULL); | ||
1185 | |||
1186 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h); | ||
1187 | |||
1188 | new_w = child_w; | ||
1189 | new_h = child_h; | ||
1190 | if (new_h > top_h) top_h = new_h; | ||
1191 | |||
1192 | _layout_set_offset_and_expand_dimension_space_max_bounded | ||
1193 | (child_h, &new_h, h, max_h, &off_y, align_y, padding_t, padding_b); | ||
1194 | |||
1195 | _layout_set_offset_and_change_dimension_min_max_cell_bounded | ||
1196 | (child_w, &new_w, min_w, max_w, cell_sz, &off_x, align_x, | ||
1197 | padding_l, padding_r); | ||
1198 | |||
1199 | if ((new_w != child_w) || (new_h != child_h)) | ||
1200 | evas_object_resize(opt->obj, new_w, new_h); | ||
1201 | evas_object_move(opt->obj, x + off_x, y + off_y); | ||
1202 | |||
1203 | x += cell_sz + global_pad; | ||
1204 | sub_pixel += pad_inc; | ||
1205 | if (sub_pixel >= 1 << 16) | ||
1206 | { | ||
1207 | x++; | ||
1208 | sub_pixel -= 1 << 16; | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | evas_object_size_hint_min_set(o, x, top_h); | ||
1213 | } | ||
1214 | |||
1215 | EAPI void | ||
1216 | evas_object_box_layout_homogeneous_max_size_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
1217 | { | ||
1218 | int remaining, global_pad, pad_inc = 0, sub_pixel = 0; | ||
1219 | int cell_sz = 0; | ||
1220 | int x, y, w, h; | ||
1221 | int top_w = 0; | ||
1222 | int n_children; | ||
1223 | Evas_Object_Box_Option *opt; | ||
1224 | Eina_List *l; | ||
1225 | |||
1226 | n_children = eina_list_count(priv->children); | ||
1227 | if (!n_children) | ||
1228 | return; | ||
1229 | |||
1230 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
1231 | |||
1232 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1233 | { | ||
1234 | int child_h, padding_t, padding_b; | ||
1235 | |||
1236 | _sizing_eval(opt->obj); | ||
1237 | evas_object_size_hint_padding_get | ||
1238 | (opt->obj, NULL, NULL, &padding_t, &padding_b); | ||
1239 | evas_object_geometry_get(opt->obj, NULL, NULL, NULL, &child_h); | ||
1240 | if (child_h + padding_t + padding_b > cell_sz) | ||
1241 | cell_sz = child_h + padding_t + padding_b; | ||
1242 | } | ||
1243 | |||
1244 | global_pad = priv->pad.v; | ||
1245 | remaining = h - n_children * cell_sz - global_pad * (n_children - 1); | ||
1246 | |||
1247 | if (priv->align.v >= 0.0) | ||
1248 | y += remaining * priv->align.v; | ||
1249 | else if (n_children == 1) | ||
1250 | y += remaining / 2; | ||
1251 | else | ||
1252 | { /* justified */ | ||
1253 | _fixed_point_divide_and_decompose_integer | ||
1254 | (remaining, n_children - 1, &global_pad, &pad_inc); | ||
1255 | global_pad += priv->pad.v; | ||
1256 | } | ||
1257 | |||
1258 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1259 | { | ||
1260 | int child_w, child_h, max_h, min_h, max_w, new_w, new_h, off_x, off_y; | ||
1261 | int padding_l, padding_r, padding_t, padding_b; | ||
1262 | double align_x, align_y; | ||
1263 | |||
1264 | evas_object_size_hint_align_get(opt->obj, &align_x, &align_y); | ||
1265 | evas_object_size_hint_padding_get | ||
1266 | (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b); | ||
1267 | evas_object_size_hint_max_get(opt->obj, &max_w, &max_h); | ||
1268 | evas_object_size_hint_min_get(opt->obj, NULL, &min_h); | ||
1269 | |||
1270 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h); | ||
1271 | |||
1272 | new_w = child_w; | ||
1273 | new_h = child_h; | ||
1274 | if (new_w > top_w) top_w = new_w; | ||
1275 | |||
1276 | _layout_set_offset_and_expand_dimension_space_max_bounded | ||
1277 | (child_w, &new_w, w, max_w, &off_x, align_x, padding_l, padding_r); | ||
1278 | |||
1279 | _layout_set_offset_and_change_dimension_min_max_cell_bounded | ||
1280 | (child_h, &new_h, min_h, max_h, cell_sz, &off_y, align_y, | ||
1281 | padding_t, padding_b); | ||
1282 | |||
1283 | if ((new_w != child_w) || (new_h != child_h)) | ||
1284 | evas_object_resize(opt->obj, new_w, new_h); | ||
1285 | evas_object_move(opt->obj, x + off_x, y + off_y); | ||
1286 | |||
1287 | y += cell_sz + global_pad; | ||
1288 | sub_pixel += pad_inc; | ||
1289 | if (sub_pixel >= 1 << 16) | ||
1290 | { | ||
1291 | y++; | ||
1292 | sub_pixel -= 1 << 16; | ||
1293 | } | ||
1294 | } | ||
1295 | |||
1296 | evas_object_size_hint_min_set(o, top_w, y); | ||
1297 | } | ||
1298 | |||
1299 | static void | ||
1300 | _evas_object_box_layout_flow_horizontal_row_info_collect(Evas_Object_Box_Data *priv, int box_w, int *row_count, int *row_max_h, int *row_break, int *row_width, int *off_y_ret, int *max_h_ret) | ||
1301 | { | ||
1302 | int i, remain_w = box_w, start_i = 0; | ||
1303 | int off_y = 0, max_h = 0, n_rows = 0; | ||
1304 | Eina_List *l; | ||
1305 | |||
1306 | for (i = 0, l = priv->children; l; i++, l = l->next) | ||
1307 | { | ||
1308 | Evas_Object_Box_Option *opt = l->data; | ||
1309 | int padding_l, padding_r, padding_t, padding_b; | ||
1310 | int child_w, child_h, off_x = 0; | ||
1311 | |||
1312 | evas_object_size_hint_padding_get | ||
1313 | (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b); | ||
1314 | |||
1315 | _sizing_eval(opt->obj); | ||
1316 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h); | ||
1317 | |||
1318 | child_w += padding_l + padding_r + priv->pad.h; | ||
1319 | child_h += padding_t + padding_b; | ||
1320 | |||
1321 | remain_w -= child_w; | ||
1322 | if (remain_w + priv->pad.h >= 0) | ||
1323 | { /* continue "line" */ | ||
1324 | if (child_h > max_h) | ||
1325 | max_h = child_h; | ||
1326 | |||
1327 | off_x += child_w; | ||
1328 | row_width[n_rows] += child_w; | ||
1329 | } | ||
1330 | else | ||
1331 | { /* break line */ | ||
1332 | if (i == start_i) | ||
1333 | { /* obj goes to actual line */ | ||
1334 | max_h = child_h; | ||
1335 | row_width[n_rows] = child_w; | ||
1336 | } | ||
1337 | else | ||
1338 | { /* obj goes to next line */ | ||
1339 | row_max_h[n_rows] = max_h; | ||
1340 | row_break[n_rows] = i - 1; | ||
1341 | n_rows++; | ||
1342 | |||
1343 | off_x = child_w; | ||
1344 | off_y += max_h; | ||
1345 | max_h = child_h; | ||
1346 | |||
1347 | row_width[n_rows] = child_w; | ||
1348 | start_i = i; | ||
1349 | |||
1350 | remain_w = box_w - off_x; | ||
1351 | } | ||
1352 | } | ||
1353 | } | ||
1354 | |||
1355 | row_break[n_rows] = i - 1; | ||
1356 | row_max_h[n_rows] = max_h; | ||
1357 | |||
1358 | *row_count = n_rows; | ||
1359 | *off_y_ret = off_y; | ||
1360 | *max_h_ret = max_h; | ||
1361 | } | ||
1362 | |||
1363 | EAPI void | ||
1364 | evas_object_box_layout_flow_horizontal(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
1365 | { | ||
1366 | int n_children, v_justify; | ||
1367 | int r, row_count = 0; | ||
1368 | int min_w = 0, min_h = 0; | ||
1369 | int max_h, inc_y; | ||
1370 | int remain_y, i; | ||
1371 | int x, y, w, h; | ||
1372 | Eina_List *l; | ||
1373 | int *row_max_h; | ||
1374 | int *row_break; | ||
1375 | int *row_width; | ||
1376 | int offset_y; | ||
1377 | |||
1378 | n_children = eina_list_count(priv->children); | ||
1379 | if (!n_children) | ||
1380 | return; | ||
1381 | |||
1382 | /* *per row* arrays */ | ||
1383 | row_max_h = (int *)alloca(sizeof(int) * n_children); | ||
1384 | if (!row_max_h) | ||
1385 | return; | ||
1386 | row_break = (int *)alloca(sizeof(int) * n_children); | ||
1387 | if (!row_break) | ||
1388 | return; | ||
1389 | row_width = (int *)alloca(sizeof(int) * n_children); | ||
1390 | if (!row_width) | ||
1391 | return; | ||
1392 | |||
1393 | memset(row_width, 0, sizeof(row_width)); | ||
1394 | |||
1395 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
1396 | |||
1397 | _evas_object_box_layout_flow_horizontal_row_info_collect | ||
1398 | (priv, w, &row_count, row_max_h, row_break, row_width, &offset_y, &max_h); | ||
1399 | |||
1400 | inc_y = 0; | ||
1401 | v_justify = 0; | ||
1402 | remain_y = h - (offset_y + max_h); | ||
1403 | |||
1404 | if (remain_y > 0) | ||
1405 | { | ||
1406 | if (priv->align.v >= 0.0) | ||
1407 | inc_y = priv->align.v * remain_y; | ||
1408 | else if (row_count == 0) | ||
1409 | y += remain_y / 2; | ||
1410 | else /* y-justified */ | ||
1411 | inc_y = remain_y / row_count; | ||
1412 | } | ||
1413 | |||
1414 | inc_y += priv->pad.v; | ||
1415 | |||
1416 | for (i = 0, r = 0, l = priv->children; r <= row_count; r++) | ||
1417 | { | ||
1418 | int row_justify = 0, just_inc = 0, sub_pixel = 0; | ||
1419 | int row_size, remain_x; | ||
1420 | |||
1421 | row_size = row_break[r] - i; | ||
1422 | remain_x = (w - row_width[r]); | ||
1423 | |||
1424 | if (priv->align.h < 0.0) | ||
1425 | { | ||
1426 | if (row_size == 0) | ||
1427 | x += remain_x / 2; | ||
1428 | else | ||
1429 | _fixed_point_divide_and_decompose_integer | ||
1430 | (remain_x, row_size, &row_justify, &just_inc); | ||
1431 | } | ||
1432 | |||
1433 | row_justify += priv->pad.h; | ||
1434 | |||
1435 | for (; i <= row_break[r]; i++, l = l->next) | ||
1436 | { | ||
1437 | Evas_Object_Box_Option *opt = l->data; | ||
1438 | int off_x, off_y, y_remain; | ||
1439 | int padding_l, padding_r; | ||
1440 | int child_w, child_h; | ||
1441 | double align_y; | ||
1442 | |||
1443 | evas_object_size_hint_align_get(opt->obj, NULL, &align_y); | ||
1444 | evas_object_size_hint_padding_get | ||
1445 | (opt->obj, &padding_l, &padding_r, NULL, NULL); | ||
1446 | |||
1447 | evas_object_geometry_get | ||
1448 | (opt->obj, NULL, NULL, &child_w, &child_h); | ||
1449 | |||
1450 | y_remain = row_max_h[r] - child_h; | ||
1451 | |||
1452 | off_x = padding_l; | ||
1453 | if (priv->align.h >= 0.0) | ||
1454 | off_x += remain_x * priv->align.h; | ||
1455 | off_y = y_remain * align_y; | ||
1456 | |||
1457 | evas_object_move(opt->obj, x + off_x, y + off_y); | ||
1458 | |||
1459 | x += child_w + padding_l + padding_r + row_justify; | ||
1460 | |||
1461 | sub_pixel += just_inc; | ||
1462 | if (sub_pixel >= 1 << 16) | ||
1463 | { | ||
1464 | x++; | ||
1465 | sub_pixel -= 1 << 16; | ||
1466 | } | ||
1467 | } | ||
1468 | |||
1469 | evas_object_geometry_get(o, &x, NULL, NULL, NULL); | ||
1470 | if (min_w < row_width[r]) | ||
1471 | min_w = row_width[r]; | ||
1472 | min_h += row_max_h[r]; | ||
1473 | y += row_max_h[r] + inc_y; | ||
1474 | } | ||
1475 | |||
1476 | evas_object_size_hint_min_set(o, min_w, min_h); | ||
1477 | } | ||
1478 | |||
1479 | static void | ||
1480 | _evas_object_box_layout_flow_vertical_col_info_collect(Evas_Object_Box_Data *priv, int box_h, int *col_count, int *col_max_w, int *col_break, int *col_height, int *off_x_ret, int *max_w_ret) | ||
1481 | { | ||
1482 | int i, remain_h = box_h, start_i = 0; | ||
1483 | int off_x = 0, max_w = 0, n_cols = 0; | ||
1484 | Eina_List *l; | ||
1485 | |||
1486 | for (i = 0, l = priv->children; l; i++, l = l->next) | ||
1487 | { | ||
1488 | Evas_Object_Box_Option *opt = l->data; | ||
1489 | int padding_l, padding_r, padding_t, padding_b; | ||
1490 | int child_w, child_h, off_y = 0; | ||
1491 | |||
1492 | evas_object_size_hint_padding_get | ||
1493 | (opt->obj, &padding_l, &padding_r, &padding_t, &padding_b); | ||
1494 | |||
1495 | _sizing_eval(opt->obj); | ||
1496 | evas_object_geometry_get(opt->obj, NULL, NULL, &child_w, &child_h); | ||
1497 | |||
1498 | child_w += padding_l + padding_r; | ||
1499 | child_h += padding_t + padding_b + priv->pad.v; | ||
1500 | |||
1501 | remain_h -= child_h; | ||
1502 | if (remain_h + priv->pad.v >= 0) | ||
1503 | { /* continue "col" */ | ||
1504 | if (child_w > max_w) | ||
1505 | max_w = child_w; | ||
1506 | |||
1507 | off_y += child_h; | ||
1508 | col_height[n_cols] += child_h; | ||
1509 | } | ||
1510 | else | ||
1511 | { | ||
1512 | /* break col */ | ||
1513 | if (i == start_i) | ||
1514 | { /* obj goes to actual col */ | ||
1515 | max_w = child_w; | ||
1516 | col_height[n_cols] = child_h; | ||
1517 | } | ||
1518 | else | ||
1519 | { /* obj goes to next col */ | ||
1520 | col_max_w[n_cols] = max_w; | ||
1521 | col_break[n_cols] = i - 1; | ||
1522 | n_cols++; | ||
1523 | |||
1524 | off_x += max_w; | ||
1525 | off_y = child_h; | ||
1526 | max_w = child_w; | ||
1527 | |||
1528 | col_height[n_cols] = child_h; | ||
1529 | start_i = i; | ||
1530 | |||
1531 | remain_h = box_h - off_y; | ||
1532 | } | ||
1533 | } | ||
1534 | } | ||
1535 | |||
1536 | col_break[n_cols] = i - 1; | ||
1537 | col_max_w[n_cols] = max_w; | ||
1538 | |||
1539 | *col_count = n_cols; | ||
1540 | *off_x_ret = off_x; | ||
1541 | *max_w_ret = max_w; | ||
1542 | } | ||
1543 | |||
1544 | EAPI void | ||
1545 | evas_object_box_layout_flow_vertical(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
1546 | { | ||
1547 | int n_children; | ||
1548 | int c, col_count; | ||
1549 | int min_w = 0, min_h = 0; | ||
1550 | int max_w, inc_x; | ||
1551 | int remain_x, i; | ||
1552 | int x, y, w, h; | ||
1553 | Eina_List *l; | ||
1554 | int *col_max_w; | ||
1555 | int *col_break; | ||
1556 | int *col_height; | ||
1557 | int offset_x; | ||
1558 | |||
1559 | n_children = eina_list_count(priv->children); | ||
1560 | if (!n_children) | ||
1561 | return; | ||
1562 | |||
1563 | /* *per col* arrays */ | ||
1564 | col_max_w = (int *)alloca(sizeof(int) * n_children); | ||
1565 | if (!col_max_w) | ||
1566 | return; | ||
1567 | col_break = (int *)alloca(sizeof(int) * n_children); | ||
1568 | if (!col_break) | ||
1569 | return; | ||
1570 | col_height = (int *)alloca(sizeof(int) * n_children); | ||
1571 | if (!col_height) | ||
1572 | return; | ||
1573 | |||
1574 | memset(col_height, 0, sizeof(col_height)); | ||
1575 | |||
1576 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
1577 | |||
1578 | _evas_object_box_layout_flow_vertical_col_info_collect | ||
1579 | (priv, h, &col_count, col_max_w, col_break, col_height, &offset_x, &max_w); | ||
1580 | |||
1581 | inc_x = 0; | ||
1582 | remain_x = w - (offset_x + max_w); | ||
1583 | |||
1584 | if (remain_x > 0) | ||
1585 | { | ||
1586 | if (priv->align.h >= 0) | ||
1587 | inc_x = priv->align.h * remain_x; | ||
1588 | else if (col_count == 0) | ||
1589 | x += remain_x / 2; | ||
1590 | else /* x-justified */ | ||
1591 | inc_x = remain_x / col_count; | ||
1592 | } | ||
1593 | |||
1594 | inc_x += priv->pad.h; | ||
1595 | |||
1596 | for (i = 0, c = 0, l = priv->children; c <= col_count; c++) | ||
1597 | { | ||
1598 | int col_justify = 0, just_inc = 0, sub_pixel = 0; | ||
1599 | int col_size, remain_y; | ||
1600 | |||
1601 | col_size = col_break[c] - i; | ||
1602 | remain_y = (h - col_height[c]); | ||
1603 | |||
1604 | if (priv->align.v < 0.0) | ||
1605 | { | ||
1606 | if (col_size == 0) | ||
1607 | y += remain_y / 2; | ||
1608 | else | ||
1609 | _fixed_point_divide_and_decompose_integer | ||
1610 | (remain_y, col_size, &col_justify, &just_inc); | ||
1611 | } | ||
1612 | |||
1613 | col_justify += priv->pad.v; | ||
1614 | |||
1615 | for (; i <= col_break[c]; i++, l = l->next) | ||
1616 | { | ||
1617 | Evas_Object_Box_Option *opt = l->data; | ||
1618 | int off_x, off_y, x_remain; | ||
1619 | int padding_t, padding_b; | ||
1620 | int child_w, child_h; | ||
1621 | double align_x; | ||
1622 | |||
1623 | evas_object_size_hint_align_get(opt->obj, &align_x, NULL); | ||
1624 | evas_object_size_hint_padding_get | ||
1625 | (opt->obj, NULL, NULL, &padding_t, &padding_b); | ||
1626 | |||
1627 | evas_object_geometry_get | ||
1628 | (opt->obj, NULL, NULL, &child_w, &child_h); | ||
1629 | |||
1630 | x_remain = col_max_w[c] - child_w; | ||
1631 | |||
1632 | off_x = x_remain * align_x; | ||
1633 | off_y = padding_t; | ||
1634 | if (priv->align.v >= 0.0) | ||
1635 | off_y += remain_y * priv->align.v; | ||
1636 | |||
1637 | evas_object_move(opt->obj, x + off_x, y + off_y); | ||
1638 | |||
1639 | y += child_h + padding_t + padding_b + col_justify; | ||
1640 | |||
1641 | sub_pixel += just_inc; | ||
1642 | if (sub_pixel >= 1 << 16) | ||
1643 | { | ||
1644 | y++; | ||
1645 | sub_pixel -= 1 << 16; | ||
1646 | } | ||
1647 | } | ||
1648 | |||
1649 | evas_object_geometry_get(o, NULL, &y, NULL, NULL); | ||
1650 | min_w += col_max_w[c]; | ||
1651 | if (min_h < col_height[c]) | ||
1652 | min_h = col_height[c]; | ||
1653 | x += col_max_w[c] + inc_x; | ||
1654 | } | ||
1655 | |||
1656 | evas_object_size_hint_min_set(o, min_w, min_h); | ||
1657 | } | ||
1658 | |||
1659 | EAPI void | ||
1660 | evas_object_box_layout_stack(Evas_Object *o, Evas_Object_Box_Data *priv, void *data __UNUSED__) | ||
1661 | { | ||
1662 | Eina_List *l; | ||
1663 | Evas_Coord ox, oy, ow, oh; | ||
1664 | Evas_Coord top_w = 0, top_h = 0; | ||
1665 | Evas_Object_Box_Option *opt; | ||
1666 | Evas_Object *old_child = NULL; | ||
1667 | |||
1668 | evas_object_geometry_get(o, &ox, &oy, &ow, &oh); | ||
1669 | |||
1670 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1671 | { | ||
1672 | Evas_Object *child = opt->obj; | ||
1673 | Evas_Coord max_w, max_h, min_w, min_h, pad_l, pad_r, pad_t, pad_b, | ||
1674 | child_w, child_h, new_w, new_h, off_x, off_y; | ||
1675 | double align_x, align_y; | ||
1676 | |||
1677 | evas_object_size_hint_align_get(child, &align_x, &align_y); | ||
1678 | evas_object_size_hint_padding_get | ||
1679 | (child, &pad_l, &pad_r, &pad_t, &pad_b); | ||
1680 | evas_object_size_hint_max_get(child, &max_w, &max_h); | ||
1681 | evas_object_size_hint_min_get(child, &min_w, &min_h); | ||
1682 | |||
1683 | _sizing_eval(opt->obj); | ||
1684 | evas_object_geometry_get(child, NULL, NULL, &child_w, &child_h); | ||
1685 | new_w = child_w; | ||
1686 | new_h = child_h; | ||
1687 | if (new_w > top_w) top_w = new_w; | ||
1688 | if (new_h > top_h) top_h = new_h; | ||
1689 | |||
1690 | _layout_set_offset_and_change_dimension_min_max_cell_bounded | ||
1691 | (child_w, &new_w, min_w, max_w, ow, &off_x, align_x, pad_l, pad_r); | ||
1692 | _layout_set_offset_and_change_dimension_min_max_cell_bounded | ||
1693 | (child_h, &new_h, min_h, max_h, oh, &off_y, align_y, pad_t, pad_b); | ||
1694 | |||
1695 | if ((new_w != child_w) || (new_h != child_h)) | ||
1696 | evas_object_resize(child, new_w, new_h); | ||
1697 | evas_object_move(child, ox + off_x, oy + off_y); | ||
1698 | |||
1699 | if (old_child) | ||
1700 | evas_object_stack_above(child, old_child); | ||
1701 | old_child = child; | ||
1702 | } | ||
1703 | |||
1704 | evas_object_size_hint_min_set(o, top_w, top_h); | ||
1705 | } | ||
1706 | |||
1707 | EAPI void | ||
1708 | evas_object_box_align_set(Evas_Object *o, double horizontal, double vertical) | ||
1709 | { | ||
1710 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv); | ||
1711 | if (priv->align.h == horizontal && priv->align.v == vertical) | ||
1712 | return; | ||
1713 | priv->align.h = horizontal; | ||
1714 | priv->align.v = vertical; | ||
1715 | evas_object_smart_changed(o); | ||
1716 | } | ||
1717 | |||
1718 | EAPI void | ||
1719 | evas_object_box_align_get(const Evas_Object *o, double *horizontal, double *vertical) | ||
1720 | { | ||
1721 | EVAS_OBJECT_BOX_DATA_GET(o, priv); | ||
1722 | if (priv) | ||
1723 | { | ||
1724 | if (horizontal) *horizontal = priv->align.h; | ||
1725 | if (vertical) *vertical = priv->align.v; | ||
1726 | } | ||
1727 | else | ||
1728 | { | ||
1729 | if (horizontal) *horizontal = 0.5; | ||
1730 | if (vertical) *vertical = 0.5; | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1734 | EAPI void | ||
1735 | evas_object_box_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical) | ||
1736 | { | ||
1737 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN(o, priv); | ||
1738 | if (priv->pad.h == horizontal && priv->pad.v == vertical) | ||
1739 | return; | ||
1740 | priv->pad.h = horizontal; | ||
1741 | priv->pad.v = vertical; | ||
1742 | evas_object_smart_changed(o); | ||
1743 | } | ||
1744 | |||
1745 | EAPI void | ||
1746 | evas_object_box_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical) | ||
1747 | { | ||
1748 | EVAS_OBJECT_BOX_DATA_GET(o, priv); | ||
1749 | if (priv) | ||
1750 | { | ||
1751 | if (horizontal) *horizontal = priv->pad.h; | ||
1752 | if (vertical) *vertical = priv->pad.v; | ||
1753 | } | ||
1754 | else | ||
1755 | { | ||
1756 | if (horizontal) *horizontal = 0; | ||
1757 | if (vertical) *vertical = 0; | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1761 | EAPI Evas_Object_Box_Option * | ||
1762 | evas_object_box_append(Evas_Object *o, Evas_Object *child) | ||
1763 | { | ||
1764 | Evas_Object_Box_Option *opt; | ||
1765 | const Evas_Object_Box_Api *api; | ||
1766 | |||
1767 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1768 | if (!child) | ||
1769 | return NULL; | ||
1770 | |||
1771 | api = priv->api; | ||
1772 | if ((!api) || (!api->append)) | ||
1773 | return NULL; | ||
1774 | |||
1775 | opt = api->append(o, priv, child); | ||
1776 | |||
1777 | if (opt) | ||
1778 | { | ||
1779 | evas_object_smart_member_add(child, o); | ||
1780 | evas_object_smart_changed(o); | ||
1781 | return _evas_object_box_option_callbacks_register(o, priv, opt); | ||
1782 | } | ||
1783 | |||
1784 | return NULL; | ||
1785 | } | ||
1786 | |||
1787 | EAPI Evas_Object_Box_Option * | ||
1788 | evas_object_box_prepend(Evas_Object *o, Evas_Object *child) | ||
1789 | { | ||
1790 | Evas_Object_Box_Option *opt; | ||
1791 | const Evas_Object_Box_Api *api; | ||
1792 | |||
1793 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1794 | if (!child) | ||
1795 | return NULL; | ||
1796 | |||
1797 | api = priv->api; | ||
1798 | if ((!api) || (!api->prepend)) | ||
1799 | return NULL; | ||
1800 | |||
1801 | opt = api->prepend(o, priv, child); | ||
1802 | |||
1803 | if (opt) | ||
1804 | { | ||
1805 | evas_object_smart_member_add(child, o); | ||
1806 | evas_object_smart_changed(o); | ||
1807 | return _evas_object_box_option_callbacks_register(o, priv, opt); | ||
1808 | } | ||
1809 | |||
1810 | return NULL; | ||
1811 | } | ||
1812 | |||
1813 | EAPI Evas_Object_Box_Option * | ||
1814 | evas_object_box_insert_before(Evas_Object *o, Evas_Object *child, const Evas_Object *reference) | ||
1815 | { | ||
1816 | Evas_Object_Box_Option *opt; | ||
1817 | const Evas_Object_Box_Api *api; | ||
1818 | |||
1819 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1820 | if (!child) | ||
1821 | return NULL; | ||
1822 | |||
1823 | api = priv->api; | ||
1824 | if ((!api) || (!api->insert_before)) | ||
1825 | return NULL; | ||
1826 | |||
1827 | opt = api->insert_before(o, priv, child, reference); | ||
1828 | |||
1829 | if (opt) | ||
1830 | { | ||
1831 | evas_object_smart_member_add(child, o); | ||
1832 | evas_object_smart_changed(o); | ||
1833 | return _evas_object_box_option_callbacks_register(o, priv, opt); | ||
1834 | } | ||
1835 | |||
1836 | return NULL; | ||
1837 | } | ||
1838 | |||
1839 | EAPI Evas_Object_Box_Option * | ||
1840 | evas_object_box_insert_after(Evas_Object *o, Evas_Object *child, const Evas_Object *reference) | ||
1841 | { | ||
1842 | Evas_Object_Box_Option *opt; | ||
1843 | const Evas_Object_Box_Api *api; | ||
1844 | |||
1845 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
1846 | if (!child) | ||
1847 | return NULL; | ||
1848 | |||
1849 | api = priv->api; | ||
1850 | if ((!api) || (!api->insert_after)) | ||
1851 | return NULL; | ||
1852 | |||
1853 | opt = api->insert_after(o, priv, child, reference); | ||
1854 | |||
1855 | if (opt) | ||
1856 | { | ||
1857 | evas_object_smart_member_add(child, o); | ||
1858 | evas_object_smart_changed(o); | ||
1859 | return _evas_object_box_option_callbacks_register(o, priv, opt); | ||
1860 | } | ||
1861 | |||
1862 | return NULL; | ||
1863 | } | ||
1864 | |||
1865 | EAPI Evas_Object_Box_Option * | ||
1866 | evas_object_box_insert_at(Evas_Object *o, Evas_Object *child, unsigned int pos) | ||
1867 | { | ||
1868 | Evas_Object_Box_Option *opt; | ||
1869 | const Evas_Object_Box_Api *api; | ||
1870 | |||
1871 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1872 | if (!child) | ||
1873 | return NULL; | ||
1874 | |||
1875 | api = priv->api; | ||
1876 | if ((!api) || (!api->insert_at)) | ||
1877 | return NULL; | ||
1878 | |||
1879 | opt = api->insert_at(o, priv, child, pos); | ||
1880 | |||
1881 | if (opt) | ||
1882 | { | ||
1883 | evas_object_smart_member_add(child, o); | ||
1884 | evas_object_smart_changed(o); | ||
1885 | return _evas_object_box_option_callbacks_register(o, priv, opt); | ||
1886 | } | ||
1887 | |||
1888 | return NULL; | ||
1889 | } | ||
1890 | |||
1891 | EAPI Eina_Bool | ||
1892 | evas_object_box_remove(Evas_Object *o, Evas_Object *child) | ||
1893 | { | ||
1894 | const Evas_Object_Box_Api *api; | ||
1895 | Evas_Object *obj; | ||
1896 | |||
1897 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1898 | if (!child) return EINA_FALSE; | ||
1899 | |||
1900 | api = priv->api; | ||
1901 | if ((!api) || (!api->remove)) | ||
1902 | return 0; | ||
1903 | |||
1904 | obj = api->remove(o, priv, child); | ||
1905 | |||
1906 | if (obj) | ||
1907 | { | ||
1908 | _evas_object_box_child_callbacks_unregister(obj); | ||
1909 | evas_object_smart_member_del(obj); | ||
1910 | evas_object_smart_changed(o); | ||
1911 | return EINA_TRUE; | ||
1912 | } | ||
1913 | |||
1914 | return EINA_FALSE; | ||
1915 | } | ||
1916 | |||
1917 | EAPI Eina_Bool | ||
1918 | evas_object_box_remove_at(Evas_Object *o, unsigned int pos) | ||
1919 | { | ||
1920 | const Evas_Object_Box_Api *api; | ||
1921 | Evas_Object *obj; | ||
1922 | |||
1923 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1924 | api = priv->api; | ||
1925 | if ((!api) || (!api->remove_at)) return EINA_FALSE; | ||
1926 | |||
1927 | obj = api->remove_at(o, priv, pos); | ||
1928 | |||
1929 | if (obj) | ||
1930 | { | ||
1931 | _evas_object_box_child_callbacks_unregister(obj); | ||
1932 | evas_object_smart_member_del(obj); | ||
1933 | evas_object_smart_changed(o); | ||
1934 | return EINA_TRUE; | ||
1935 | } | ||
1936 | |||
1937 | return EINA_FALSE; | ||
1938 | } | ||
1939 | |||
1940 | EAPI Eina_Bool | ||
1941 | evas_object_box_remove_all(Evas_Object *o, Eina_Bool clear) | ||
1942 | { | ||
1943 | const Evas_Object_Box_Api *api; | ||
1944 | |||
1945 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1946 | |||
1947 | api = priv->api; | ||
1948 | if ((!api) || (!api->remove)) return EINA_FALSE; | ||
1949 | |||
1950 | evas_object_smart_changed(o); | ||
1951 | |||
1952 | while (priv->children) | ||
1953 | { | ||
1954 | Evas_Object_Box_Option *opt = priv->children->data; | ||
1955 | Evas_Object *obj; | ||
1956 | |||
1957 | obj = api->remove(o, priv, opt->obj); | ||
1958 | if (obj) | ||
1959 | { | ||
1960 | _evas_object_box_child_callbacks_unregister(obj); | ||
1961 | evas_object_smart_member_del(obj); | ||
1962 | if (clear) | ||
1963 | evas_object_del(obj); | ||
1964 | } | ||
1965 | else return EINA_FALSE; | ||
1966 | } | ||
1967 | |||
1968 | return EINA_TRUE; | ||
1969 | } | ||
1970 | |||
1971 | EAPI Eina_Iterator * | ||
1972 | evas_object_box_iterator_new(const Evas_Object *o) | ||
1973 | { | ||
1974 | Evas_Object_Box_Iterator *it; | ||
1975 | |||
1976 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
1977 | |||
1978 | if (!priv->children) return NULL; | ||
1979 | |||
1980 | it = calloc(1, sizeof(Evas_Object_Box_Iterator)); | ||
1981 | if (!it) return NULL; | ||
1982 | |||
1983 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
1984 | |||
1985 | it->real_iterator = eina_list_iterator_new(priv->children); | ||
1986 | it->box = o; | ||
1987 | |||
1988 | it->iterator.next = FUNC_ITERATOR_NEXT(_evas_object_box_iterator_next); | ||
1989 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_evas_object_box_iterator_get_container); | ||
1990 | it->iterator.free = FUNC_ITERATOR_FREE(_evas_object_box_iterator_free); | ||
1991 | |||
1992 | return &it->iterator; | ||
1993 | } | ||
1994 | |||
1995 | EAPI Eina_Accessor * | ||
1996 | evas_object_box_accessor_new(const Evas_Object *o) | ||
1997 | { | ||
1998 | Evas_Object_Box_Accessor *it; | ||
1999 | |||
2000 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
2001 | |||
2002 | if (!priv->children) return NULL; | ||
2003 | |||
2004 | it = calloc(1, sizeof(Evas_Object_Box_Accessor)); | ||
2005 | if (!it) return NULL; | ||
2006 | |||
2007 | EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR); | ||
2008 | |||
2009 | it->real_accessor = eina_list_accessor_new(priv->children); | ||
2010 | it->box = o; | ||
2011 | |||
2012 | it->accessor.get_at = FUNC_ACCESSOR_GET_AT(_evas_object_box_accessor_get_at); | ||
2013 | it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(_evas_object_box_accessor_get_container); | ||
2014 | it->accessor.free = FUNC_ACCESSOR_FREE(_evas_object_box_accessor_free); | ||
2015 | |||
2016 | return &it->accessor; | ||
2017 | } | ||
2018 | |||
2019 | EAPI Eina_List * | ||
2020 | evas_object_box_children_get(const Evas_Object *o) | ||
2021 | { | ||
2022 | Eina_List *new_list = NULL, *l; | ||
2023 | Evas_Object_Box_Option *opt; | ||
2024 | |||
2025 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
2026 | |||
2027 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
2028 | new_list = eina_list_append(new_list, opt->obj); | ||
2029 | |||
2030 | return new_list; | ||
2031 | } | ||
2032 | |||
2033 | EAPI const char * | ||
2034 | evas_object_box_option_property_name_get(Evas_Object *o, int property) | ||
2035 | { | ||
2036 | const Evas_Object_Box_Api *api; | ||
2037 | |||
2038 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
2039 | |||
2040 | if (property < 0) | ||
2041 | return NULL; | ||
2042 | |||
2043 | api = priv->api; | ||
2044 | if ((!api) || (!api->property_name_get)) | ||
2045 | return NULL; | ||
2046 | |||
2047 | return api->property_name_get(o, property); | ||
2048 | } | ||
2049 | |||
2050 | EAPI int | ||
2051 | evas_object_box_option_property_id_get(Evas_Object *o, const char *name) | ||
2052 | { | ||
2053 | const Evas_Object_Box_Api *api; | ||
2054 | |||
2055 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, -1); | ||
2056 | |||
2057 | if (!name) | ||
2058 | return -1; | ||
2059 | |||
2060 | api = priv->api; | ||
2061 | if ((!api) || (!api->property_id_get)) | ||
2062 | return -1; | ||
2063 | |||
2064 | return api->property_id_get(o, name); | ||
2065 | } | ||
2066 | |||
2067 | EAPI Eina_Bool | ||
2068 | evas_object_box_option_property_set(Evas_Object *o, Evas_Object_Box_Option *opt, int property, ...) | ||
2069 | { | ||
2070 | Eina_Bool ret; | ||
2071 | va_list args; | ||
2072 | |||
2073 | va_start(args, property); | ||
2074 | ret = evas_object_box_option_property_vset(o, opt, property, args); | ||
2075 | va_end(args); | ||
2076 | |||
2077 | return ret; | ||
2078 | } | ||
2079 | |||
2080 | |||
2081 | EAPI Eina_Bool | ||
2082 | evas_object_box_option_property_vset(Evas_Object *o, Evas_Object_Box_Option *opt, int property, va_list args) | ||
2083 | { | ||
2084 | const Evas_Object_Box_Api *api; | ||
2085 | |||
2086 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
2087 | |||
2088 | if (!opt) return EINA_FALSE; | ||
2089 | |||
2090 | api = priv->api; | ||
2091 | if ((!api) || (!api->property_set)) | ||
2092 | return EINA_FALSE; | ||
2093 | |||
2094 | if (!api->property_set(o, opt, property, args)) | ||
2095 | return EINA_FALSE; | ||
2096 | |||
2097 | evas_object_smart_changed(o); | ||
2098 | return EINA_TRUE; | ||
2099 | } | ||
2100 | |||
2101 | EAPI Eina_Bool | ||
2102 | evas_object_box_option_property_get(Evas_Object *o, Evas_Object_Box_Option *opt, int property, ...) | ||
2103 | { | ||
2104 | Eina_Bool ret; | ||
2105 | va_list args; | ||
2106 | |||
2107 | va_start(args, property); | ||
2108 | ret = evas_object_box_option_property_vget(o, opt, property, args); | ||
2109 | va_end(args); | ||
2110 | |||
2111 | return ret; | ||
2112 | } | ||
2113 | |||
2114 | EAPI Eina_Bool | ||
2115 | evas_object_box_option_property_vget(Evas_Object *o, Evas_Object_Box_Option *opt, int property, va_list args) | ||
2116 | { | ||
2117 | const Evas_Object_Box_Api *api; | ||
2118 | |||
2119 | EVAS_OBJECT_BOX_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
2120 | |||
2121 | if (!opt) return EINA_FALSE; | ||
2122 | |||
2123 | api = priv->api; | ||
2124 | if ((!api) || (!api->property_get)) | ||
2125 | return EINA_FALSE; | ||
2126 | |||
2127 | return api->property_get(o, opt, property, args); | ||
2128 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_grid.c b/libraries/evas/src/lib/canvas/evas_object_grid.c new file mode 100644 index 0000000..ac96f04 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_grid.c | |||
@@ -0,0 +1,465 @@ | |||
1 | #include <errno.h> | ||
2 | #include "evas_common.h" | ||
3 | |||
4 | typedef struct _Evas_Object_Grid_Data Evas_Object_Grid_Data; | ||
5 | typedef struct _Evas_Object_Grid_Option Evas_Object_Grid_Option; | ||
6 | typedef struct _Evas_Object_Grid_Iterator Evas_Object_Grid_Iterator; | ||
7 | typedef struct _Evas_Object_Grid_Accessor Evas_Object_Grid_Accessor; | ||
8 | |||
9 | struct _Evas_Object_Grid_Option | ||
10 | { | ||
11 | Evas_Object *obj; | ||
12 | Eina_List *l; | ||
13 | int x, y, w, h; | ||
14 | }; | ||
15 | |||
16 | struct _Evas_Object_Grid_Data | ||
17 | { | ||
18 | Evas_Object_Smart_Clipped_Data base; | ||
19 | Eina_List *children; | ||
20 | struct { | ||
21 | int w, h; | ||
22 | } size; | ||
23 | Eina_Bool is_mirrored : 1; | ||
24 | }; | ||
25 | |||
26 | struct _Evas_Object_Grid_Iterator | ||
27 | { | ||
28 | Eina_Iterator iterator; | ||
29 | |||
30 | Eina_Iterator *real_iterator; | ||
31 | const Evas_Object *grid; | ||
32 | }; | ||
33 | |||
34 | struct _Evas_Object_Grid_Accessor | ||
35 | { | ||
36 | Eina_Accessor accessor; | ||
37 | |||
38 | Eina_Accessor *real_accessor; | ||
39 | const Evas_Object *grid; | ||
40 | }; | ||
41 | |||
42 | #define EVAS_OBJECT_GRID_DATA_GET(o, ptr) \ | ||
43 | Evas_Object_Grid_Data *ptr = evas_object_smart_data_get(o) | ||
44 | |||
45 | #define EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, ptr) \ | ||
46 | EVAS_OBJECT_GRID_DATA_GET(o, ptr); \ | ||
47 | if (!ptr) \ | ||
48 | { \ | ||
49 | CRIT("no widget data for object %p (%s)", \ | ||
50 | o, evas_object_type_get(o)); \ | ||
51 | abort(); \ | ||
52 | return; \ | ||
53 | } | ||
54 | |||
55 | #define EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, ptr, val) \ | ||
56 | EVAS_OBJECT_GRID_DATA_GET(o, ptr); \ | ||
57 | if (!ptr) \ | ||
58 | { \ | ||
59 | CRIT("No widget data for object %p (%s)", \ | ||
60 | o, evas_object_type_get(o)); \ | ||
61 | abort(); \ | ||
62 | return val; \ | ||
63 | } | ||
64 | |||
65 | static const char EVAS_OBJECT_GRID_OPTION_KEY[] = "|EvGd"; | ||
66 | |||
67 | static Eina_Bool | ||
68 | _evas_object_grid_iterator_next(Evas_Object_Grid_Iterator *it, void **data) | ||
69 | { | ||
70 | Evas_Object_Grid_Option *opt; | ||
71 | |||
72 | if (!eina_iterator_next(it->real_iterator, (void **)&opt)) | ||
73 | return EINA_FALSE; | ||
74 | if (data) *data = opt->obj; | ||
75 | return EINA_TRUE; | ||
76 | } | ||
77 | |||
78 | static Evas_Object * | ||
79 | _evas_object_grid_iterator_get_container(Evas_Object_Grid_Iterator *it) | ||
80 | { | ||
81 | return (Evas_Object *)it->grid; | ||
82 | } | ||
83 | |||
84 | static void | ||
85 | _evas_object_grid_iterator_free(Evas_Object_Grid_Iterator *it) | ||
86 | { | ||
87 | eina_iterator_free(it->real_iterator); | ||
88 | free(it); | ||
89 | } | ||
90 | |||
91 | static Eina_Bool | ||
92 | _evas_object_grid_accessor_get_at(Evas_Object_Grid_Accessor *it, unsigned int idx, void **data) | ||
93 | { | ||
94 | Evas_Object_Grid_Option *opt = NULL; | ||
95 | |||
96 | if (!eina_accessor_data_get(it->real_accessor, idx, (void **)&opt)) | ||
97 | return EINA_FALSE; | ||
98 | if (data) *data = opt->obj; | ||
99 | return EINA_TRUE; | ||
100 | } | ||
101 | |||
102 | static Evas_Object * | ||
103 | _evas_object_grid_accessor_get_container(Evas_Object_Grid_Accessor *it) | ||
104 | { | ||
105 | return (Evas_Object *)it->grid; | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | _evas_object_grid_accessor_free(Evas_Object_Grid_Accessor *it) | ||
110 | { | ||
111 | eina_accessor_free(it->real_accessor); | ||
112 | free(it); | ||
113 | } | ||
114 | |||
115 | static Evas_Object_Grid_Option * | ||
116 | _evas_object_grid_option_get(Evas_Object *o) | ||
117 | { | ||
118 | return evas_object_data_get(o, EVAS_OBJECT_GRID_OPTION_KEY); | ||
119 | } | ||
120 | |||
121 | static void | ||
122 | _evas_object_grid_option_set(Evas_Object *o, const Evas_Object_Grid_Option *opt) | ||
123 | { | ||
124 | evas_object_data_set(o, EVAS_OBJECT_GRID_OPTION_KEY, opt); | ||
125 | } | ||
126 | |||
127 | static Evas_Object_Grid_Option * | ||
128 | _evas_object_grid_option_del(Evas_Object *o) | ||
129 | { | ||
130 | return evas_object_data_del(o, EVAS_OBJECT_GRID_OPTION_KEY); | ||
131 | } | ||
132 | |||
133 | static void | ||
134 | _on_child_del(void *data, Evas *evas __UNUSED__, Evas_Object *child, void *einfo __UNUSED__) | ||
135 | { | ||
136 | Evas_Object *grid = data; | ||
137 | evas_object_grid_unpack(grid, child); | ||
138 | } | ||
139 | |||
140 | static void | ||
141 | _evas_object_grid_child_connect(Evas_Object *o, Evas_Object *child) | ||
142 | { | ||
143 | evas_object_event_callback_add | ||
144 | (child, EVAS_CALLBACK_DEL, _on_child_del, o); | ||
145 | } | ||
146 | |||
147 | static void | ||
148 | _evas_object_grid_child_disconnect(Evas_Object *o, Evas_Object *child) | ||
149 | { | ||
150 | evas_object_event_callback_del_full | ||
151 | (child, EVAS_CALLBACK_DEL, _on_child_del, o); | ||
152 | } | ||
153 | |||
154 | EVAS_SMART_SUBCLASS_NEW("Evas_Object_Grid", _evas_object_grid, | ||
155 | Evas_Smart_Class, Evas_Smart_Class, | ||
156 | evas_object_smart_clipped_class_get, NULL) | ||
157 | |||
158 | static void | ||
159 | _evas_object_grid_smart_add(Evas_Object *o) | ||
160 | { | ||
161 | EVAS_SMART_DATA_ALLOC(o, Evas_Object_Grid_Data) | ||
162 | |||
163 | priv->size.w = 100; | ||
164 | priv->size.h = 100; | ||
165 | |||
166 | _evas_object_grid_parent_sc->add(o); | ||
167 | } | ||
168 | |||
169 | static void | ||
170 | _evas_object_grid_smart_del(Evas_Object *o) | ||
171 | { | ||
172 | EVAS_OBJECT_GRID_DATA_GET(o, priv); | ||
173 | Eina_List *l; | ||
174 | |||
175 | l = priv->children; | ||
176 | while (l) | ||
177 | { | ||
178 | Evas_Object_Grid_Option *opt = l->data; | ||
179 | _evas_object_grid_child_disconnect(o, opt->obj); | ||
180 | _evas_object_grid_option_del(opt->obj); | ||
181 | free(opt); | ||
182 | l = eina_list_remove_list(l, l); | ||
183 | } | ||
184 | _evas_object_grid_parent_sc->del(o); | ||
185 | } | ||
186 | |||
187 | static void | ||
188 | _evas_object_grid_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h) | ||
189 | { | ||
190 | Evas_Coord ow, oh; | ||
191 | evas_object_geometry_get(o, NULL, NULL, &ow, &oh); | ||
192 | if ((ow == w) && (oh == h)) return; | ||
193 | evas_object_smart_changed(o); | ||
194 | } | ||
195 | |||
196 | static void | ||
197 | _evas_object_grid_smart_calculate(Evas_Object *o) | ||
198 | { | ||
199 | Eina_List *l; | ||
200 | Evas_Object_Grid_Option *opt; | ||
201 | Evas_Coord x, y, w, h, vw, vh, t; | ||
202 | Eina_Bool mirror; | ||
203 | |||
204 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv); | ||
205 | if (!priv) return; | ||
206 | if (!priv->children) return; | ||
207 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
208 | mirror = priv->is_mirrored; | ||
209 | vw = priv->size.w; | ||
210 | vh = priv->size.h; | ||
211 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
212 | { | ||
213 | Evas_Coord x1, y1, x2, y2; | ||
214 | |||
215 | x1 = x + ((w * opt->x) / vw); | ||
216 | y1 = y + ((h * opt->y) / vh); | ||
217 | x2 = x + ((w * (opt->x + opt->w)) / vw); | ||
218 | y2 = y + ((h * (opt->y + opt->h)) / vh); | ||
219 | if (mirror) | ||
220 | { | ||
221 | t = x1; x1 = x2; x2 = t; | ||
222 | t = y1; y1 = y2; y2 = t; | ||
223 | } | ||
224 | evas_object_move(opt->obj, x1, y1); | ||
225 | evas_object_resize(opt->obj, x2 - x1, y2 - y1); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static void | ||
230 | _evas_object_grid_smart_set_user(Evas_Smart_Class *sc) | ||
231 | { | ||
232 | sc->add = _evas_object_grid_smart_add; | ||
233 | sc->del = _evas_object_grid_smart_del; | ||
234 | sc->resize = _evas_object_grid_smart_resize; | ||
235 | sc->calculate = _evas_object_grid_smart_calculate; | ||
236 | } | ||
237 | |||
238 | EAPI Evas_Object * | ||
239 | evas_object_grid_add(Evas *evas) | ||
240 | { | ||
241 | return evas_object_smart_add(evas, _evas_object_grid_smart_class_new()); | ||
242 | } | ||
243 | |||
244 | EAPI Evas_Object * | ||
245 | evas_object_grid_add_to(Evas_Object *parent) | ||
246 | { | ||
247 | Evas *evas; | ||
248 | Evas_Object *o; | ||
249 | |||
250 | evas = evas_object_evas_get(parent); | ||
251 | o = evas_object_grid_add(evas); | ||
252 | evas_object_smart_member_add(o, parent); | ||
253 | return o; | ||
254 | } | ||
255 | |||
256 | EAPI void | ||
257 | evas_object_grid_size_set(Evas_Object *o, int w, int h) | ||
258 | { | ||
259 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv); | ||
260 | if ((priv->size.w == w) && (priv->size.h == h)) return; | ||
261 | priv->size.w = w; | ||
262 | priv->size.h = h; | ||
263 | evas_object_smart_changed(o); | ||
264 | } | ||
265 | |||
266 | EAPI void | ||
267 | evas_object_grid_size_get(const Evas_Object *o, int *w, int *h) | ||
268 | { | ||
269 | if (w) *w = 0; | ||
270 | if (h) *h = 0; | ||
271 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv); | ||
272 | if (w) *w = priv->size.w; | ||
273 | if (h) *h = priv->size.h; | ||
274 | } | ||
275 | |||
276 | EAPI Eina_Bool | ||
277 | evas_object_grid_pack(Evas_Object *o, Evas_Object *child, int x, int y, int w, int h) | ||
278 | { | ||
279 | Evas_Object_Grid_Option *opt; | ||
280 | Eina_Bool newobj = EINA_FALSE; | ||
281 | |||
282 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
283 | |||
284 | opt = _evas_object_grid_option_get(child); | ||
285 | if (!opt) | ||
286 | { | ||
287 | opt = malloc(sizeof(*opt)); | ||
288 | if (!opt) | ||
289 | { | ||
290 | ERR("could not allocate grid option data."); | ||
291 | return EINA_FALSE; | ||
292 | } | ||
293 | newobj = EINA_TRUE; | ||
294 | } | ||
295 | |||
296 | opt->x = x; | ||
297 | opt->y = y; | ||
298 | opt->w = w; | ||
299 | opt->h = h; | ||
300 | |||
301 | if (newobj) | ||
302 | { | ||
303 | opt->obj = child; | ||
304 | priv->children = eina_list_append(priv->children, opt); | ||
305 | opt->l = eina_list_last(priv->children); | ||
306 | _evas_object_grid_option_set(child, opt); | ||
307 | evas_object_smart_member_add(child, o); | ||
308 | _evas_object_grid_child_connect(o, child); | ||
309 | } | ||
310 | // FIXME: we could keep a changed list | ||
311 | evas_object_smart_changed(o); | ||
312 | return EINA_TRUE; | ||
313 | } | ||
314 | |||
315 | static void | ||
316 | _evas_object_grid_remove_opt(Evas_Object_Grid_Data *priv, Evas_Object_Grid_Option *opt) | ||
317 | { | ||
318 | priv->children = eina_list_remove_list(priv->children, opt->l); | ||
319 | opt->l = NULL; | ||
320 | } | ||
321 | |||
322 | EAPI Eina_Bool | ||
323 | evas_object_grid_unpack(Evas_Object *o, Evas_Object *child) | ||
324 | { | ||
325 | Evas_Object_Grid_Option *opt; | ||
326 | |||
327 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
328 | |||
329 | if (o != evas_object_smart_parent_get(child)) | ||
330 | { | ||
331 | ERR("cannot unpack child from incorrect grid!"); | ||
332 | return EINA_FALSE; | ||
333 | } | ||
334 | |||
335 | opt = _evas_object_grid_option_del(child); | ||
336 | if (!opt) | ||
337 | { | ||
338 | ERR("cannot unpack child with no packing option!"); | ||
339 | return EINA_FALSE; | ||
340 | } | ||
341 | |||
342 | _evas_object_grid_child_disconnect(o, child); | ||
343 | _evas_object_grid_remove_opt(priv, opt); | ||
344 | evas_object_smart_member_del(child); | ||
345 | free(opt); | ||
346 | return EINA_TRUE; | ||
347 | } | ||
348 | |||
349 | EAPI void | ||
350 | evas_object_grid_clear(Evas_Object *o, Eina_Bool clear) | ||
351 | { | ||
352 | Evas_Object_Grid_Option *opt; | ||
353 | |||
354 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv); | ||
355 | |||
356 | EINA_LIST_FREE(priv->children, opt) | ||
357 | { | ||
358 | _evas_object_grid_child_disconnect(o, opt->obj); | ||
359 | _evas_object_grid_option_del(opt->obj); | ||
360 | evas_object_smart_member_del(opt->obj); | ||
361 | if (clear) | ||
362 | evas_object_del(opt->obj); | ||
363 | free(opt); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | EAPI Eina_Bool | ||
368 | evas_object_grid_pack_get(Evas_Object *o, Evas_Object *child, int *x, int *y, int *w, int *h) | ||
369 | { | ||
370 | Evas_Object_Grid_Option *opt; | ||
371 | |||
372 | if (x) *x = 0; | ||
373 | if (y) *y = 0; | ||
374 | if (w) *w = 0; | ||
375 | if (h) *h = 0; | ||
376 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
377 | opt = _evas_object_grid_option_get(child); | ||
378 | if (!opt) return 0; | ||
379 | if (x) *x = opt->x; | ||
380 | if (y) *y = opt->y; | ||
381 | if (w) *w = opt->w; | ||
382 | if (h) *h = opt->h; | ||
383 | return 1; | ||
384 | } | ||
385 | |||
386 | EAPI Eina_Iterator * | ||
387 | evas_object_grid_iterator_new(const Evas_Object *o) | ||
388 | { | ||
389 | Evas_Object_Grid_Iterator *it; | ||
390 | |||
391 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
392 | |||
393 | if (!priv->children) return NULL; | ||
394 | |||
395 | it = calloc(1, sizeof(Evas_Object_Grid_Iterator)); | ||
396 | if (!it) return NULL; | ||
397 | |||
398 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
399 | |||
400 | it->real_iterator = eina_list_iterator_new(priv->children); | ||
401 | it->grid = o; | ||
402 | |||
403 | it->iterator.next = FUNC_ITERATOR_NEXT(_evas_object_grid_iterator_next); | ||
404 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_evas_object_grid_iterator_get_container); | ||
405 | it->iterator.free = FUNC_ITERATOR_FREE(_evas_object_grid_iterator_free); | ||
406 | |||
407 | return &it->iterator; | ||
408 | } | ||
409 | |||
410 | EAPI Eina_Accessor * | ||
411 | evas_object_grid_accessor_new(const Evas_Object *o) | ||
412 | { | ||
413 | Evas_Object_Grid_Accessor *it; | ||
414 | |||
415 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
416 | |||
417 | if (!priv->children) return NULL; | ||
418 | |||
419 | it = calloc(1, sizeof(Evas_Object_Grid_Accessor)); | ||
420 | if (!it) return NULL; | ||
421 | |||
422 | EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR); | ||
423 | |||
424 | it->real_accessor = eina_list_accessor_new(priv->children); | ||
425 | it->grid = o; | ||
426 | |||
427 | it->accessor.get_at = FUNC_ACCESSOR_GET_AT(_evas_object_grid_accessor_get_at); | ||
428 | it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(_evas_object_grid_accessor_get_container); | ||
429 | it->accessor.free = FUNC_ACCESSOR_FREE(_evas_object_grid_accessor_free); | ||
430 | |||
431 | return &it->accessor; | ||
432 | } | ||
433 | |||
434 | EAPI Eina_List * | ||
435 | evas_object_grid_children_get(const Evas_Object *o) | ||
436 | { | ||
437 | Eina_List *new_list = NULL, *l; | ||
438 | Evas_Object_Grid_Option *opt; | ||
439 | |||
440 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
441 | |||
442 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
443 | new_list = eina_list_append(new_list, opt->obj); | ||
444 | |||
445 | return new_list; | ||
446 | } | ||
447 | |||
448 | EAPI Eina_Bool | ||
449 | evas_object_grid_mirrored_get(const Evas_Object *obj) | ||
450 | { | ||
451 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(obj, priv, EINA_FALSE); | ||
452 | return priv->is_mirrored; | ||
453 | } | ||
454 | |||
455 | EAPI void | ||
456 | evas_object_grid_mirrored_set(Evas_Object *obj, Eina_Bool mirrored) | ||
457 | { | ||
458 | EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(obj, priv); | ||
459 | mirrored = !!mirrored; | ||
460 | if (priv->is_mirrored != mirrored) | ||
461 | { | ||
462 | priv->is_mirrored = mirrored; | ||
463 | _evas_object_grid_smart_calculate(obj); | ||
464 | } | ||
465 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_image.c b/libraries/evas/src/lib/canvas/evas_object_image.c new file mode 100644 index 0000000..7f757a6 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_image.c | |||
@@ -0,0 +1,3895 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <unistd.h> | ||
3 | #include <stdlib.h> | ||
4 | #include <sys/mman.h> | ||
5 | #include <math.h> | ||
6 | |||
7 | #include "evas_common.h" | ||
8 | #include "evas_private.h" | ||
9 | #include "../engines/common/evas_convert_color.h" | ||
10 | #include "../engines/common/evas_convert_colorspace.h" | ||
11 | #include "../engines/common/evas_convert_yuv.h" | ||
12 | |||
13 | #define VERBOSE_PROXY_ERROR 1 | ||
14 | |||
15 | /* private magic number for image objects */ | ||
16 | static const char o_type[] = "image"; | ||
17 | |||
18 | /* private struct for rectangle object internal data */ | ||
19 | typedef struct _Evas_Object_Image Evas_Object_Image; | ||
20 | |||
21 | struct _Evas_Object_Image | ||
22 | { | ||
23 | DATA32 magic; | ||
24 | |||
25 | struct { | ||
26 | int spread; | ||
27 | Evas_Coord_Rectangle fill; | ||
28 | struct { | ||
29 | short w, h, stride; | ||
30 | } image; | ||
31 | struct { | ||
32 | short l, r, t, b; | ||
33 | unsigned char fill; | ||
34 | double scale; | ||
35 | } border; | ||
36 | |||
37 | Evas_Object *source; | ||
38 | Evas_Map *defmap; | ||
39 | const char *file; | ||
40 | const char *key; | ||
41 | int frame; | ||
42 | Evas_Colorspace cspace; | ||
43 | |||
44 | unsigned char smooth_scale : 1; | ||
45 | unsigned char has_alpha :1; | ||
46 | unsigned char opaque :1; | ||
47 | unsigned char opaque_valid :1; | ||
48 | } cur, prev; | ||
49 | |||
50 | int pixels_checked_out; | ||
51 | int load_error; | ||
52 | Eina_List *pixel_updates; | ||
53 | |||
54 | struct { | ||
55 | unsigned char scale_down_by; | ||
56 | double dpi; | ||
57 | short w, h; | ||
58 | struct { | ||
59 | short x, y, w, h; | ||
60 | } region; | ||
61 | Eina_Bool orientation : 1; | ||
62 | } load_opts; | ||
63 | |||
64 | struct { | ||
65 | Evas_Object_Image_Pixels_Get_Cb get_pixels; | ||
66 | void *get_pixels_data; | ||
67 | } func; | ||
68 | |||
69 | Evas_Video_Surface video; | ||
70 | |||
71 | const char *tmpf; | ||
72 | int tmpf_fd; | ||
73 | |||
74 | Evas_Image_Scale_Hint scale_hint; | ||
75 | Evas_Image_Content_Hint content_hint; | ||
76 | |||
77 | void *engine_data; | ||
78 | |||
79 | unsigned char changed : 1; | ||
80 | unsigned char dirty_pixels : 1; | ||
81 | unsigned char filled : 1; | ||
82 | unsigned char proxyrendering : 1; | ||
83 | unsigned char preloading : 1; | ||
84 | unsigned char video_rendering : 1; | ||
85 | unsigned char video_surface : 1; | ||
86 | unsigned char video_visible : 1; | ||
87 | unsigned char created : 1; | ||
88 | }; | ||
89 | |||
90 | /* private methods for image objects */ | ||
91 | static void evas_object_image_unload(Evas_Object *obj, Eina_Bool dirty); | ||
92 | static void evas_object_image_load(Evas_Object *obj); | ||
93 | static Evas_Coord evas_object_image_figure_x_fill(Evas_Object *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret); | ||
94 | static Evas_Coord evas_object_image_figure_y_fill(Evas_Object *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret); | ||
95 | |||
96 | static void evas_object_image_init(Evas_Object *obj); | ||
97 | static void *evas_object_image_new(void); | ||
98 | static void evas_object_image_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y); | ||
99 | static void evas_object_image_free(Evas_Object *obj); | ||
100 | static void evas_object_image_render_pre(Evas_Object *obj); | ||
101 | static void evas_object_image_render_post(Evas_Object *obj); | ||
102 | |||
103 | static unsigned int evas_object_image_id_get(Evas_Object *obj); | ||
104 | static unsigned int evas_object_image_visual_id_get(Evas_Object *obj); | ||
105 | static void *evas_object_image_engine_data_get(Evas_Object *obj); | ||
106 | |||
107 | static int evas_object_image_is_opaque(Evas_Object *obj); | ||
108 | static int evas_object_image_was_opaque(Evas_Object *obj); | ||
109 | static int evas_object_image_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y); | ||
110 | static int evas_object_image_has_opaque_rect(Evas_Object *obj); | ||
111 | static int evas_object_image_get_opaque_rect(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h); | ||
112 | static int evas_object_image_can_map(Evas_Object *obj); | ||
113 | |||
114 | static void *evas_object_image_data_convert_internal(Evas_Object_Image *o, void *data, Evas_Colorspace to_cspace); | ||
115 | static void evas_object_image_filled_resize_listener(void *data, Evas *e, Evas_Object *obj, void *einfo); | ||
116 | |||
117 | static void _proxy_unset(Evas_Object *proxy); | ||
118 | static void _proxy_set(Evas_Object *proxy, Evas_Object *src); | ||
119 | static void _proxy_error(Evas_Object *proxy, void *context, void *output, void *surface, int x, int y); | ||
120 | |||
121 | static void _cleanup_tmpf(Evas_Object *obj); | ||
122 | |||
123 | static const Evas_Object_Func object_func = | ||
124 | { | ||
125 | /* methods (compulsory) */ | ||
126 | evas_object_image_free, | ||
127 | evas_object_image_render, | ||
128 | evas_object_image_render_pre, | ||
129 | evas_object_image_render_post, | ||
130 | evas_object_image_id_get, | ||
131 | evas_object_image_visual_id_get, | ||
132 | evas_object_image_engine_data_get, | ||
133 | /* these are optional. NULL = nothing */ | ||
134 | NULL, | ||
135 | NULL, | ||
136 | NULL, | ||
137 | NULL, | ||
138 | evas_object_image_is_opaque, | ||
139 | evas_object_image_was_opaque, | ||
140 | evas_object_image_is_inside, | ||
141 | NULL, | ||
142 | NULL, | ||
143 | NULL, | ||
144 | evas_object_image_has_opaque_rect, | ||
145 | evas_object_image_get_opaque_rect, | ||
146 | evas_object_image_can_map | ||
147 | }; | ||
148 | |||
149 | EVAS_MEMPOOL(_mp_obj); | ||
150 | |||
151 | static void | ||
152 | _evas_object_image_cleanup(Evas_Object *obj, Evas_Object_Image *o) | ||
153 | { | ||
154 | if ((o->preloading) && (o->engine_data)) | ||
155 | { | ||
156 | o->preloading = 0; | ||
157 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
158 | o->engine_data, | ||
159 | obj); | ||
160 | } | ||
161 | if (o->tmpf) _cleanup_tmpf(obj); | ||
162 | if (o->cur.source) _proxy_unset(obj); | ||
163 | } | ||
164 | |||
165 | EAPI Evas_Object * | ||
166 | evas_object_image_add(Evas *e) | ||
167 | { | ||
168 | Evas_Object *obj; | ||
169 | Evas_Object_Image *o; | ||
170 | |||
171 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
172 | return NULL; | ||
173 | MAGIC_CHECK_END(); | ||
174 | obj = evas_object_new(e); | ||
175 | evas_object_image_init(obj); | ||
176 | evas_object_inject(obj, e); | ||
177 | o = (Evas_Object_Image *)(obj->object_data); | ||
178 | o->cur.cspace = obj->layer->evas->engine.func->image_colorspace_get(obj->layer->evas->engine.data.output, | ||
179 | o->engine_data); | ||
180 | return obj; | ||
181 | } | ||
182 | |||
183 | EAPI Evas_Object * | ||
184 | evas_object_image_filled_add(Evas *e) | ||
185 | { | ||
186 | Evas_Object *obj; | ||
187 | obj = evas_object_image_add(e); | ||
188 | evas_object_image_filled_set(obj, 1); | ||
189 | return obj; | ||
190 | } | ||
191 | |||
192 | static void | ||
193 | _cleanup_tmpf(Evas_Object *obj) | ||
194 | { | ||
195 | Evas_Object_Image *o; | ||
196 | |||
197 | o = (Evas_Object_Image *)(obj->object_data); | ||
198 | if (!o->tmpf) return; | ||
199 | #ifdef __linux__ | ||
200 | #else | ||
201 | unlink(o->tmpf); | ||
202 | #endif | ||
203 | if (o->tmpf_fd >= 0) close(o->tmpf_fd); | ||
204 | eina_stringshare_del(o->tmpf); | ||
205 | o->tmpf_fd = -1; | ||
206 | o->tmpf = NULL; | ||
207 | } | ||
208 | |||
209 | static void | ||
210 | _create_tmpf(Evas_Object *obj, void *data, int size, char *format __UNUSED__) | ||
211 | { | ||
212 | Evas_Object_Image *o; | ||
213 | char buf[4096]; | ||
214 | void *dst; | ||
215 | int fd = -1; | ||
216 | |||
217 | o = (Evas_Object_Image *)(obj->object_data); | ||
218 | #ifdef __linux__ | ||
219 | snprintf(buf, sizeof(buf), "/dev/shm/.evas-tmpf-%i-%p-%i-XXXXXX", | ||
220 | (int)getpid(), data, (int)size); | ||
221 | fd = mkstemp(buf); | ||
222 | #endif | ||
223 | if (fd < 0) | ||
224 | { | ||
225 | snprintf(buf, sizeof(buf), "/tmp/.evas-tmpf-%i-%p-%i-XXXXXX", | ||
226 | (int)getpid(), data, (int)size); | ||
227 | fd = mkstemp(buf); | ||
228 | } | ||
229 | if (fd < 0) return; | ||
230 | if (ftruncate(fd, size) < 0) | ||
231 | { | ||
232 | unlink(buf); | ||
233 | close(fd); | ||
234 | return; | ||
235 | } | ||
236 | unlink(buf); | ||
237 | |||
238 | eina_mmap_safety_enabled_set(EINA_TRUE); | ||
239 | |||
240 | dst = mmap(NULL, size, | ||
241 | PROT_READ | PROT_WRITE, | ||
242 | MAP_SHARED, | ||
243 | fd, 0); | ||
244 | if (dst == MAP_FAILED) | ||
245 | { | ||
246 | close(fd); | ||
247 | return; | ||
248 | } | ||
249 | o->tmpf_fd = fd; | ||
250 | #ifdef __linux__ | ||
251 | snprintf(buf, sizeof(buf), "/proc/%li/fd/%i", (long)getpid(), fd); | ||
252 | #endif | ||
253 | o->tmpf = eina_stringshare_add(buf); | ||
254 | memcpy(dst, data, size); | ||
255 | munmap(dst, size); | ||
256 | } | ||
257 | |||
258 | EAPI void | ||
259 | evas_object_image_memfile_set(Evas_Object *obj, void *data, int size, char *format, char *key) | ||
260 | { | ||
261 | Evas_Object_Image *o; | ||
262 | |||
263 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
264 | return; | ||
265 | MAGIC_CHECK_END(); | ||
266 | o = (Evas_Object_Image *)(obj->object_data); | ||
267 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
268 | return; | ||
269 | MAGIC_CHECK_END(); | ||
270 | _cleanup_tmpf(obj); | ||
271 | evas_object_image_file_set(obj, NULL, NULL); | ||
272 | // invalidate the cache effectively | ||
273 | evas_object_image_alpha_set(obj, !o->cur.has_alpha); | ||
274 | evas_object_image_alpha_set(obj, !o->cur.has_alpha); | ||
275 | |||
276 | if ((size < 1) || (!data)) return; | ||
277 | |||
278 | _create_tmpf(obj, data, size, format); | ||
279 | evas_object_image_file_set(obj, o->tmpf, key); | ||
280 | if (!o->engine_data) | ||
281 | { | ||
282 | ERR("unable to load '%s' from memory", o->tmpf); | ||
283 | _cleanup_tmpf(obj); | ||
284 | return; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | EAPI void | ||
289 | evas_object_image_file_set(Evas_Object *obj, const char *file, const char *key) | ||
290 | { | ||
291 | Evas_Object_Image *o; | ||
292 | Evas_Image_Load_Opts lo; | ||
293 | |||
294 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
295 | return; | ||
296 | MAGIC_CHECK_END(); | ||
297 | o = (Evas_Object_Image *)(obj->object_data); | ||
298 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
299 | return; | ||
300 | MAGIC_CHECK_END(); | ||
301 | if ((o->tmpf) && (file != o->tmpf)) _cleanup_tmpf(obj); | ||
302 | if ((o->cur.file) && (file) && (!strcmp(o->cur.file, file))) | ||
303 | { | ||
304 | if ((!o->cur.key) && (!key)) | ||
305 | return; | ||
306 | if ((o->cur.key) && (key) && (!strcmp(o->cur.key, key))) | ||
307 | return; | ||
308 | } | ||
309 | /* | ||
310 | * WTF? why cancel a null image preload? this is just silly (tm) | ||
311 | if (!o->engine_data) | ||
312 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
313 | o->engine_data, | ||
314 | obj); | ||
315 | */ | ||
316 | if (o->cur.source) _proxy_unset(obj); | ||
317 | if (o->cur.file) eina_stringshare_del(o->cur.file); | ||
318 | if (o->cur.key) eina_stringshare_del(o->cur.key); | ||
319 | if (file) o->cur.file = eina_stringshare_add(file); | ||
320 | else o->cur.file = NULL; | ||
321 | if (key) o->cur.key = eina_stringshare_add(key); | ||
322 | else o->cur.key = NULL; | ||
323 | o->prev.file = NULL; | ||
324 | o->prev.key = NULL; | ||
325 | if (o->engine_data) | ||
326 | { | ||
327 | if (o->preloading) | ||
328 | { | ||
329 | o->preloading = 0; | ||
330 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
331 | o->engine_data, | ||
332 | obj); | ||
333 | } | ||
334 | obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output, | ||
335 | o->engine_data); | ||
336 | } | ||
337 | o->load_error = EVAS_LOAD_ERROR_NONE; | ||
338 | lo.scale_down_by = o->load_opts.scale_down_by; | ||
339 | lo.dpi = o->load_opts.dpi; | ||
340 | lo.w = o->load_opts.w; | ||
341 | lo.h = o->load_opts.h; | ||
342 | lo.region.x = o->load_opts.region.x; | ||
343 | lo.region.y = o->load_opts.region.y; | ||
344 | lo.region.w = o->load_opts.region.w; | ||
345 | lo.region.h = o->load_opts.region.h; | ||
346 | lo.orientation = o->load_opts.orientation; | ||
347 | o->engine_data = obj->layer->evas->engine.func->image_load(obj->layer->evas->engine.data.output, | ||
348 | o->cur.file, | ||
349 | o->cur.key, | ||
350 | &o->load_error, | ||
351 | &lo); | ||
352 | if (o->engine_data) | ||
353 | { | ||
354 | int w, h; | ||
355 | int stride; | ||
356 | |||
357 | obj->layer->evas->engine.func->image_size_get(obj->layer->evas->engine.data.output, | ||
358 | o->engine_data, &w, &h); | ||
359 | if (obj->layer->evas->engine.func->image_stride_get) | ||
360 | obj->layer->evas->engine.func->image_stride_get(obj->layer->evas->engine.data.output, | ||
361 | o->engine_data, &stride); | ||
362 | else | ||
363 | stride = w * 4; | ||
364 | o->cur.has_alpha = obj->layer->evas->engine.func->image_alpha_get(obj->layer->evas->engine.data.output, | ||
365 | o->engine_data); | ||
366 | o->cur.cspace = obj->layer->evas->engine.func->image_colorspace_get(obj->layer->evas->engine.data.output, | ||
367 | o->engine_data); | ||
368 | o->cur.image.w = w; | ||
369 | o->cur.image.h = h; | ||
370 | o->cur.image.stride = stride; | ||
371 | } | ||
372 | else | ||
373 | { | ||
374 | if (o->load_error == EVAS_LOAD_ERROR_NONE) | ||
375 | o->load_error = EVAS_LOAD_ERROR_GENERIC; | ||
376 | o->cur.has_alpha = 1; | ||
377 | o->cur.cspace = EVAS_COLORSPACE_ARGB8888; | ||
378 | o->cur.image.w = 0; | ||
379 | o->cur.image.h = 0; | ||
380 | o->cur.image.stride = 0; | ||
381 | } | ||
382 | o->changed = 1; | ||
383 | evas_object_change(obj); | ||
384 | } | ||
385 | |||
386 | EAPI void | ||
387 | evas_object_image_file_get(const Evas_Object *obj, const char **file, const char **key) | ||
388 | { | ||
389 | Evas_Object_Image *o; | ||
390 | |||
391 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
392 | if (file) *file = NULL; | ||
393 | if (key) *key = NULL; | ||
394 | return; | ||
395 | MAGIC_CHECK_END(); | ||
396 | o = (Evas_Object_Image *)(obj->object_data); | ||
397 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
398 | if (file) *file = NULL; | ||
399 | if (key) *key = NULL; | ||
400 | return; | ||
401 | MAGIC_CHECK_END(); | ||
402 | if (file) *file = o->cur.file; | ||
403 | if (key) *key = o->cur.key; | ||
404 | } | ||
405 | |||
406 | EAPI Eina_Bool | ||
407 | evas_object_image_source_set(Evas_Object *obj, Evas_Object *src) | ||
408 | { | ||
409 | Evas_Object_Image *o; | ||
410 | |||
411 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
412 | return EINA_FALSE; | ||
413 | MAGIC_CHECK_END(); | ||
414 | o = obj->object_data; | ||
415 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
416 | return EINA_FALSE; | ||
417 | MAGIC_CHECK_END(); | ||
418 | |||
419 | if (src == obj) return EINA_FALSE; | ||
420 | if (o->cur.source == src) return EINA_TRUE; | ||
421 | |||
422 | _evas_object_image_cleanup(obj, o); | ||
423 | /* Kill the image if any */ | ||
424 | if (o->cur.file || o->cur.key) | ||
425 | evas_object_image_file_set(obj, NULL, NULL); | ||
426 | |||
427 | if (src) | ||
428 | { | ||
429 | _proxy_set(obj, src); | ||
430 | } | ||
431 | |||
432 | return EINA_TRUE; | ||
433 | } | ||
434 | |||
435 | |||
436 | EAPI Evas_Object * | ||
437 | evas_object_image_source_get(Evas_Object *obj) | ||
438 | { | ||
439 | Evas_Object_Image *o; | ||
440 | |||
441 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
442 | return NULL; | ||
443 | MAGIC_CHECK_END(); | ||
444 | o = obj->object_data; | ||
445 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
446 | return NULL; | ||
447 | MAGIC_CHECK_END(); | ||
448 | |||
449 | return o->cur.source; | ||
450 | } | ||
451 | |||
452 | EAPI Eina_Bool | ||
453 | evas_object_image_source_unset(Evas_Object *obj) | ||
454 | { | ||
455 | return evas_object_image_source_set(obj, NULL); | ||
456 | } | ||
457 | |||
458 | EAPI void | ||
459 | evas_object_image_border_set(Evas_Object *obj, int l, int r, int t, int b) | ||
460 | { | ||
461 | Evas_Object_Image *o; | ||
462 | |||
463 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
464 | return; | ||
465 | MAGIC_CHECK_END(); | ||
466 | o = (Evas_Object_Image *)(obj->object_data); | ||
467 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
468 | return; | ||
469 | MAGIC_CHECK_END(); | ||
470 | if (l < 0) l = 0; | ||
471 | if (r < 0) r = 0; | ||
472 | if (t < 0) t = 0; | ||
473 | if (b < 0) b = 0; | ||
474 | if ((o->cur.border.l == l) && | ||
475 | (o->cur.border.r == r) && | ||
476 | (o->cur.border.t == t) && | ||
477 | (o->cur.border.b == b)) return; | ||
478 | o->cur.border.l = l; | ||
479 | o->cur.border.r = r; | ||
480 | o->cur.border.t = t; | ||
481 | o->cur.border.b = b; | ||
482 | o->cur.opaque_valid = 0; | ||
483 | o->changed = 1; | ||
484 | evas_object_change(obj); | ||
485 | } | ||
486 | |||
487 | EAPI void | ||
488 | evas_object_image_border_get(const Evas_Object *obj, int *l, int *r, int *t, int *b) | ||
489 | { | ||
490 | Evas_Object_Image *o; | ||
491 | |||
492 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
493 | if (l) *l = 0; | ||
494 | if (r) *r = 0; | ||
495 | if (t) *t = 0; | ||
496 | if (b) *b = 0; | ||
497 | return; | ||
498 | MAGIC_CHECK_END(); | ||
499 | o = (Evas_Object_Image *)(obj->object_data); | ||
500 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
501 | if (l) *l = 0; | ||
502 | if (r) *r = 0; | ||
503 | if (t) *t = 0; | ||
504 | if (b) *b = 0; | ||
505 | return; | ||
506 | MAGIC_CHECK_END(); | ||
507 | if (l) *l = o->cur.border.l; | ||
508 | if (r) *r = o->cur.border.r; | ||
509 | if (t) *t = o->cur.border.t; | ||
510 | if (b) *b = o->cur.border.b; | ||
511 | } | ||
512 | |||
513 | EAPI void | ||
514 | evas_object_image_border_center_fill_set(Evas_Object *obj, Evas_Border_Fill_Mode fill) | ||
515 | { | ||
516 | Evas_Object_Image *o; | ||
517 | |||
518 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
519 | return; | ||
520 | MAGIC_CHECK_END(); | ||
521 | o = (Evas_Object_Image *)(obj->object_data); | ||
522 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
523 | return; | ||
524 | MAGIC_CHECK_END(); | ||
525 | if (fill == o->cur.border.fill) return; | ||
526 | o->cur.border.fill = fill; | ||
527 | o->changed = 1; | ||
528 | evas_object_change(obj); | ||
529 | } | ||
530 | |||
531 | EAPI Evas_Border_Fill_Mode | ||
532 | evas_object_image_border_center_fill_get(const Evas_Object *obj) | ||
533 | { | ||
534 | Evas_Object_Image *o; | ||
535 | |||
536 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
537 | return 0; | ||
538 | MAGIC_CHECK_END(); | ||
539 | o = (Evas_Object_Image *)(obj->object_data); | ||
540 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
541 | return 0; | ||
542 | MAGIC_CHECK_END(); | ||
543 | return o->cur.border.fill; | ||
544 | } | ||
545 | |||
546 | EAPI void | ||
547 | evas_object_image_filled_set(Evas_Object *obj, Eina_Bool setting) | ||
548 | { | ||
549 | Evas_Object_Image *o; | ||
550 | |||
551 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
552 | return; | ||
553 | MAGIC_CHECK_END(); | ||
554 | o = (Evas_Object_Image *)(obj->object_data); | ||
555 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
556 | return; | ||
557 | MAGIC_CHECK_END(); | ||
558 | |||
559 | setting = !!setting; | ||
560 | if (o->filled == setting) return; | ||
561 | |||
562 | o->filled = setting; | ||
563 | if (!o->filled) | ||
564 | evas_object_event_callback_del(obj, EVAS_CALLBACK_RESIZE, evas_object_image_filled_resize_listener); | ||
565 | else | ||
566 | { | ||
567 | Evas_Coord w, h; | ||
568 | |||
569 | evas_object_geometry_get(obj, NULL, NULL, &w, &h); | ||
570 | evas_object_image_fill_set(obj, 0, 0, w, h); | ||
571 | |||
572 | evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, evas_object_image_filled_resize_listener, NULL); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | EAPI Eina_Bool | ||
577 | evas_object_image_filled_get(const Evas_Object *obj) | ||
578 | { | ||
579 | Evas_Object_Image *o; | ||
580 | |||
581 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
582 | return 0; | ||
583 | MAGIC_CHECK_END(); | ||
584 | o = (Evas_Object_Image *)(obj->object_data); | ||
585 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
586 | return 0; | ||
587 | MAGIC_CHECK_END(); | ||
588 | |||
589 | return o->filled; | ||
590 | } | ||
591 | |||
592 | EAPI void | ||
593 | evas_object_image_border_scale_set(Evas_Object *obj, double scale) | ||
594 | { | ||
595 | Evas_Object_Image *o; | ||
596 | |||
597 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
598 | return; | ||
599 | MAGIC_CHECK_END(); | ||
600 | o = (Evas_Object_Image *)(obj->object_data); | ||
601 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
602 | return; | ||
603 | MAGIC_CHECK_END(); | ||
604 | if (scale == o->cur.border.scale) return; | ||
605 | o->cur.border.scale = scale; | ||
606 | o->changed = 1; | ||
607 | evas_object_change(obj); | ||
608 | } | ||
609 | |||
610 | EAPI double | ||
611 | evas_object_image_border_scale_get(const Evas_Object *obj) | ||
612 | { | ||
613 | Evas_Object_Image *o; | ||
614 | |||
615 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
616 | return 1.0; | ||
617 | MAGIC_CHECK_END(); | ||
618 | o = (Evas_Object_Image *)(obj->object_data); | ||
619 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
620 | return 1.0; | ||
621 | MAGIC_CHECK_END(); | ||
622 | return o->cur.border.scale; | ||
623 | } | ||
624 | |||
625 | EAPI void | ||
626 | evas_object_image_fill_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) | ||
627 | { | ||
628 | Evas_Object_Image *o; | ||
629 | |||
630 | if (w < 0) w = -w; | ||
631 | if (h < 0) h = -h; | ||
632 | if (w == 0) return; | ||
633 | if (h == 0) return; | ||
634 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
635 | return; | ||
636 | MAGIC_CHECK_END(); | ||
637 | o = (Evas_Object_Image *)(obj->object_data); | ||
638 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
639 | return; | ||
640 | MAGIC_CHECK_END(); | ||
641 | if ((o->cur.fill.x == x) && | ||
642 | (o->cur.fill.y == y) && | ||
643 | (o->cur.fill.w == w) && | ||
644 | (o->cur.fill.h == h)) return; | ||
645 | o->cur.fill.x = x; | ||
646 | o->cur.fill.y = y; | ||
647 | o->cur.fill.w = w; | ||
648 | o->cur.fill.h = h; | ||
649 | o->cur.opaque_valid = 0; | ||
650 | o->changed = 1; | ||
651 | evas_object_change(obj); | ||
652 | } | ||
653 | |||
654 | EAPI void | ||
655 | evas_object_image_fill_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) | ||
656 | { | ||
657 | Evas_Object_Image *o; | ||
658 | |||
659 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
660 | if (x) *x = 0; | ||
661 | if (y) *y = 0; | ||
662 | if (w) *w = 0; | ||
663 | if (h) *h = 0; | ||
664 | return; | ||
665 | MAGIC_CHECK_END(); | ||
666 | o = (Evas_Object_Image *)(obj->object_data); | ||
667 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
668 | if (x) *x = 0; | ||
669 | if (y) *y = 0; | ||
670 | if (w) *w = 0; | ||
671 | if (h) *h = 0; | ||
672 | return; | ||
673 | MAGIC_CHECK_END(); | ||
674 | if (x) *x = o->cur.fill.x; | ||
675 | if (y) *y = o->cur.fill.y; | ||
676 | if (w) *w = o->cur.fill.w; | ||
677 | if (h) *h = o->cur.fill.h; | ||
678 | } | ||
679 | |||
680 | |||
681 | EAPI void | ||
682 | evas_object_image_fill_spread_set(Evas_Object *obj, Evas_Fill_Spread spread) | ||
683 | { | ||
684 | Evas_Object_Image *o; | ||
685 | |||
686 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
687 | return; | ||
688 | MAGIC_CHECK_END(); | ||
689 | o = (Evas_Object_Image *)(obj->object_data); | ||
690 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
691 | return; | ||
692 | MAGIC_CHECK_END(); | ||
693 | if (spread == (Evas_Fill_Spread)o->cur.spread) return; | ||
694 | o->cur.spread = spread; | ||
695 | o->changed = 1; | ||
696 | evas_object_change(obj); | ||
697 | } | ||
698 | |||
699 | EAPI Evas_Fill_Spread | ||
700 | evas_object_image_fill_spread_get(const Evas_Object *obj) | ||
701 | { | ||
702 | Evas_Object_Image *o; | ||
703 | |||
704 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
705 | return EVAS_TEXTURE_REPEAT; | ||
706 | MAGIC_CHECK_END(); | ||
707 | o = (Evas_Object_Image *)(obj->object_data); | ||
708 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
709 | return EVAS_TEXTURE_REPEAT; | ||
710 | MAGIC_CHECK_END(); | ||
711 | return (Evas_Fill_Spread)o->cur.spread; | ||
712 | } | ||
713 | |||
714 | EAPI void | ||
715 | evas_object_image_size_set(Evas_Object *obj, int w, int h) | ||
716 | { | ||
717 | Evas_Object_Image *o; | ||
718 | int stride = 0; | ||
719 | |||
720 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
721 | return; | ||
722 | MAGIC_CHECK_END(); | ||
723 | o = (Evas_Object_Image *)(obj->object_data); | ||
724 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
725 | return; | ||
726 | MAGIC_CHECK_END(); | ||
727 | _evas_object_image_cleanup(obj, o); | ||
728 | if (w < 1) w = 1; | ||
729 | if (h < 1) h = 1; | ||
730 | if (w > 32768) return; | ||
731 | if (h > 32768) return; | ||
732 | if ((w == o->cur.image.w) && | ||
733 | (h == o->cur.image.h)) return; | ||
734 | o->cur.image.w = w; | ||
735 | o->cur.image.h = h; | ||
736 | if (o->engine_data) | ||
737 | o->engine_data = obj->layer->evas->engine.func->image_size_set(obj->layer->evas->engine.data.output, | ||
738 | o->engine_data, | ||
739 | w, h); | ||
740 | else | ||
741 | o->engine_data = obj->layer->evas->engine.func->image_new_from_copied_data | ||
742 | (obj->layer->evas->engine.data.output, w, h, NULL, o->cur.has_alpha, | ||
743 | o->cur.cspace); | ||
744 | |||
745 | if (o->engine_data) | ||
746 | { | ||
747 | if (obj->layer->evas->engine.func->image_scale_hint_set) | ||
748 | obj->layer->evas->engine.func->image_scale_hint_set | ||
749 | (obj->layer->evas->engine.data.output, | ||
750 | o->engine_data, o->scale_hint); | ||
751 | if (obj->layer->evas->engine.func->image_content_hint_set) | ||
752 | obj->layer->evas->engine.func->image_content_hint_set | ||
753 | (obj->layer->evas->engine.data.output, | ||
754 | o->engine_data, o->content_hint); | ||
755 | if (obj->layer->evas->engine.func->image_stride_get) | ||
756 | obj->layer->evas->engine.func->image_stride_get | ||
757 | (obj->layer->evas->engine.data.output, | ||
758 | o->engine_data, &stride); | ||
759 | else | ||
760 | stride = w * 4; | ||
761 | } | ||
762 | else | ||
763 | stride = w * 4; | ||
764 | o->cur.image.stride = stride; | ||
765 | |||
766 | /* FIXME - in engine call above | ||
767 | if (o->engine_data) | ||
768 | o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output, | ||
769 | o->engine_data, | ||
770 | o->cur.has_alpha); | ||
771 | */ | ||
772 | EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o); | ||
773 | o->changed = 1; | ||
774 | evas_object_change(obj); | ||
775 | } | ||
776 | |||
777 | EAPI void | ||
778 | evas_object_image_size_get(const Evas_Object *obj, int *w, int *h) | ||
779 | { | ||
780 | Evas_Object_Image *o; | ||
781 | |||
782 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
783 | if (w) *w = 0; | ||
784 | if (h) *h = 0; | ||
785 | return; | ||
786 | MAGIC_CHECK_END(); | ||
787 | o = (Evas_Object_Image *)(obj->object_data); | ||
788 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
789 | if (w) *w = 0; | ||
790 | if (h) *h = 0; | ||
791 | return; | ||
792 | MAGIC_CHECK_END(); | ||
793 | if (w) *w = o->cur.image.w; | ||
794 | if (h) *h = o->cur.image.h; | ||
795 | } | ||
796 | |||
797 | EAPI int | ||
798 | evas_object_image_stride_get(const Evas_Object *obj) | ||
799 | { | ||
800 | Evas_Object_Image *o; | ||
801 | |||
802 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
803 | return 0; | ||
804 | MAGIC_CHECK_END(); | ||
805 | o = (Evas_Object_Image *)(obj->object_data); | ||
806 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
807 | return 0; | ||
808 | MAGIC_CHECK_END(); | ||
809 | return o->cur.image.stride; | ||
810 | } | ||
811 | |||
812 | EAPI Evas_Load_Error | ||
813 | evas_object_image_load_error_get(const Evas_Object *obj) | ||
814 | { | ||
815 | Evas_Object_Image *o; | ||
816 | |||
817 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
818 | return 0; | ||
819 | MAGIC_CHECK_END(); | ||
820 | o = (Evas_Object_Image *)(obj->object_data); | ||
821 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
822 | return 0; | ||
823 | MAGIC_CHECK_END(); | ||
824 | return o->load_error; | ||
825 | } | ||
826 | |||
827 | EAPI void * | ||
828 | evas_object_image_data_convert(Evas_Object *obj, Evas_Colorspace to_cspace) | ||
829 | { | ||
830 | Evas_Object_Image *o; | ||
831 | DATA32 *data; | ||
832 | |||
833 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
834 | return NULL; | ||
835 | MAGIC_CHECK_END(); | ||
836 | o = (Evas_Object_Image *)(obj->object_data); | ||
837 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
838 | return NULL; | ||
839 | MAGIC_CHECK_END(); | ||
840 | if ((o->preloading) && (o->engine_data)) | ||
841 | { | ||
842 | o->preloading = 0; | ||
843 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
844 | o->engine_data, | ||
845 | obj); | ||
846 | } | ||
847 | if (!o->engine_data) return NULL; | ||
848 | if (o->video_surface) | ||
849 | o->video.update_pixels(o->video.data, obj, &o->video); | ||
850 | if (o->cur.cspace == to_cspace) return NULL; | ||
851 | data = NULL; | ||
852 | o->engine_data = obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output, | ||
853 | o->engine_data, | ||
854 | 0, | ||
855 | &data, | ||
856 | &o->load_error); | ||
857 | return evas_object_image_data_convert_internal(o, data, to_cspace); | ||
858 | } | ||
859 | |||
860 | EAPI void | ||
861 | evas_object_image_data_set(Evas_Object *obj, void *data) | ||
862 | { | ||
863 | Evas_Object_Image *o; | ||
864 | void *p_data; | ||
865 | |||
866 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
867 | return; | ||
868 | MAGIC_CHECK_END(); | ||
869 | o = (Evas_Object_Image *)(obj->object_data); | ||
870 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
871 | return; | ||
872 | MAGIC_CHECK_END(); | ||
873 | _evas_object_image_cleanup(obj, o); | ||
874 | #ifdef EVAS_FRAME_QUEUING | ||
875 | if (o->engine_data) | ||
876 | evas_common_pipe_op_image_flush(o->engine_data); | ||
877 | #endif | ||
878 | p_data = o->engine_data; | ||
879 | if (data) | ||
880 | { | ||
881 | if (o->engine_data) | ||
882 | o->engine_data = obj->layer->evas->engine.func->image_data_put(obj->layer->evas->engine.data.output, | ||
883 | o->engine_data, | ||
884 | data); | ||
885 | else | ||
886 | o->engine_data = obj->layer->evas->engine.func->image_new_from_data(obj->layer->evas->engine.data.output, | ||
887 | o->cur.image.w, | ||
888 | o->cur.image.h, | ||
889 | data, | ||
890 | o->cur.has_alpha, | ||
891 | o->cur.cspace); | ||
892 | if (o->engine_data) | ||
893 | { | ||
894 | int stride = 0; | ||
895 | |||
896 | if (obj->layer->evas->engine.func->image_scale_hint_set) | ||
897 | obj->layer->evas->engine.func->image_scale_hint_set | ||
898 | (obj->layer->evas->engine.data.output, | ||
899 | o->engine_data, o->scale_hint); | ||
900 | if (obj->layer->evas->engine.func->image_content_hint_set) | ||
901 | obj->layer->evas->engine.func->image_content_hint_set | ||
902 | (obj->layer->evas->engine.data.output, | ||
903 | o->engine_data, o->content_hint); | ||
904 | if (obj->layer->evas->engine.func->image_stride_get) | ||
905 | obj->layer->evas->engine.func->image_stride_get | ||
906 | (obj->layer->evas->engine.data.output, | ||
907 | o->engine_data, &stride); | ||
908 | else | ||
909 | stride = o->cur.image.w * 4; | ||
910 | o->cur.image.stride = stride; | ||
911 | } | ||
912 | } | ||
913 | else | ||
914 | { | ||
915 | if (o->engine_data) | ||
916 | obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output, | ||
917 | o->engine_data); | ||
918 | o->load_error = EVAS_LOAD_ERROR_NONE; | ||
919 | o->cur.image.w = 0; | ||
920 | o->cur.image.h = 0; | ||
921 | o->cur.image.stride = 0; | ||
922 | o->engine_data = NULL; | ||
923 | } | ||
924 | /* FIXME - in engine call above | ||
925 | if (o->engine_data) | ||
926 | o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output, | ||
927 | o->engine_data, | ||
928 | o->cur.has_alpha); | ||
929 | */ | ||
930 | if (o->pixels_checked_out > 0) o->pixels_checked_out--; | ||
931 | if (p_data != o->engine_data) | ||
932 | { | ||
933 | EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o); | ||
934 | o->pixels_checked_out = 0; | ||
935 | } | ||
936 | o->changed = 1; | ||
937 | evas_object_change(obj); | ||
938 | } | ||
939 | |||
940 | EAPI void * | ||
941 | evas_object_image_data_get(const Evas_Object *obj, Eina_Bool for_writing) | ||
942 | { | ||
943 | Evas_Object_Image *o; | ||
944 | DATA32 *data; | ||
945 | |||
946 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
947 | return NULL; | ||
948 | MAGIC_CHECK_END(); | ||
949 | o = (Evas_Object_Image *)(obj->object_data); | ||
950 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
951 | return NULL; | ||
952 | MAGIC_CHECK_END(); | ||
953 | if (!o->engine_data) return NULL; | ||
954 | #ifdef EVAS_FRAME_QUEUING | ||
955 | evas_common_pipe_op_image_flush(o->engine_data); | ||
956 | #endif | ||
957 | |||
958 | data = NULL; | ||
959 | if (obj->layer->evas->engine.func->image_scale_hint_set) | ||
960 | obj->layer->evas->engine.func->image_scale_hint_set | ||
961 | (obj->layer->evas->engine.data.output, | ||
962 | o->engine_data, o->scale_hint); | ||
963 | if (obj->layer->evas->engine.func->image_content_hint_set) | ||
964 | obj->layer->evas->engine.func->image_content_hint_set | ||
965 | (obj->layer->evas->engine.data.output, | ||
966 | o->engine_data, o->content_hint); | ||
967 | o->engine_data = obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output, | ||
968 | o->engine_data, | ||
969 | for_writing, | ||
970 | &data, | ||
971 | &o->load_error); | ||
972 | |||
973 | /* if we fail to get engine_data, we have to return NULL */ | ||
974 | if (!o->engine_data) return NULL; | ||
975 | |||
976 | if (o->engine_data) | ||
977 | { | ||
978 | int stride = 0; | ||
979 | |||
980 | if (obj->layer->evas->engine.func->image_stride_get) | ||
981 | obj->layer->evas->engine.func->image_stride_get | ||
982 | (obj->layer->evas->engine.data.output, | ||
983 | o->engine_data, &stride); | ||
984 | else | ||
985 | stride = o->cur.image.w * 4; | ||
986 | o->cur.image.stride = stride; | ||
987 | } | ||
988 | o->pixels_checked_out++; | ||
989 | if (for_writing) | ||
990 | { | ||
991 | EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o); | ||
992 | } | ||
993 | |||
994 | return data; | ||
995 | } | ||
996 | |||
997 | EAPI void | ||
998 | evas_object_image_preload(Evas_Object *obj, Eina_Bool cancel) | ||
999 | { | ||
1000 | Evas_Object_Image *o; | ||
1001 | |||
1002 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1003 | return ; | ||
1004 | MAGIC_CHECK_END(); | ||
1005 | o = (Evas_Object_Image *)(obj->object_data); | ||
1006 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1007 | return ; | ||
1008 | MAGIC_CHECK_END(); | ||
1009 | if (!o->engine_data) | ||
1010 | { | ||
1011 | o->preloading = 1; | ||
1012 | evas_object_inform_call_image_preloaded(obj); | ||
1013 | return; | ||
1014 | } | ||
1015 | // FIXME: if already busy preloading, then dont request again until | ||
1016 | // preload done | ||
1017 | if (cancel) | ||
1018 | { | ||
1019 | if (o->preloading) | ||
1020 | { | ||
1021 | o->preloading = 0; | ||
1022 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
1023 | o->engine_data, | ||
1024 | obj); | ||
1025 | } | ||
1026 | } | ||
1027 | else | ||
1028 | { | ||
1029 | if (!o->preloading) | ||
1030 | { | ||
1031 | o->preloading = 1; | ||
1032 | obj->layer->evas->engine.func->image_data_preload_request(obj->layer->evas->engine.data.output, | ||
1033 | o->engine_data, | ||
1034 | obj); | ||
1035 | } | ||
1036 | } | ||
1037 | } | ||
1038 | |||
1039 | EAPI void | ||
1040 | evas_object_image_data_copy_set(Evas_Object *obj, void *data) | ||
1041 | { | ||
1042 | Evas_Object_Image *o; | ||
1043 | |||
1044 | if (!data) return; | ||
1045 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1046 | return; | ||
1047 | MAGIC_CHECK_END(); | ||
1048 | o = (Evas_Object_Image *)(obj->object_data); | ||
1049 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1050 | return; | ||
1051 | MAGIC_CHECK_END(); | ||
1052 | _evas_object_image_cleanup(obj, o); | ||
1053 | if ((o->cur.image.w <= 0) || | ||
1054 | (o->cur.image.h <= 0)) return; | ||
1055 | if (o->engine_data) | ||
1056 | obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output, | ||
1057 | o->engine_data); | ||
1058 | o->engine_data = obj->layer->evas->engine.func->image_new_from_copied_data(obj->layer->evas->engine.data.output, | ||
1059 | o->cur.image.w, | ||
1060 | o->cur.image.h, | ||
1061 | data, | ||
1062 | o->cur.has_alpha, | ||
1063 | o->cur.cspace); | ||
1064 | if (o->engine_data) | ||
1065 | { | ||
1066 | int stride = 0; | ||
1067 | |||
1068 | o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output, | ||
1069 | o->engine_data, | ||
1070 | o->cur.has_alpha); | ||
1071 | if (obj->layer->evas->engine.func->image_scale_hint_set) | ||
1072 | obj->layer->evas->engine.func->image_scale_hint_set | ||
1073 | (obj->layer->evas->engine.data.output, | ||
1074 | o->engine_data, o->scale_hint); | ||
1075 | if (obj->layer->evas->engine.func->image_content_hint_set) | ||
1076 | obj->layer->evas->engine.func->image_content_hint_set | ||
1077 | (obj->layer->evas->engine.data.output, | ||
1078 | o->engine_data, o->content_hint); | ||
1079 | if (obj->layer->evas->engine.func->image_stride_get) | ||
1080 | obj->layer->evas->engine.func->image_stride_get | ||
1081 | (obj->layer->evas->engine.data.output, | ||
1082 | o->engine_data, &stride); | ||
1083 | else | ||
1084 | stride = o->cur.image.w * 4; | ||
1085 | o->cur.image.stride = stride; | ||
1086 | } | ||
1087 | o->pixels_checked_out = 0; | ||
1088 | EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o); | ||
1089 | } | ||
1090 | |||
1091 | EAPI void | ||
1092 | evas_object_image_data_update_add(Evas_Object *obj, int x, int y, int w, int h) | ||
1093 | { | ||
1094 | Evas_Object_Image *o; | ||
1095 | Eina_Rectangle *r; | ||
1096 | |||
1097 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1098 | return; | ||
1099 | MAGIC_CHECK_END(); | ||
1100 | o = (Evas_Object_Image *)(obj->object_data); | ||
1101 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1102 | return; | ||
1103 | MAGIC_CHECK_END(); | ||
1104 | RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, o->cur.image.w, o->cur.image.h); | ||
1105 | if ((w <= 0) || (h <= 0)) return; | ||
1106 | NEW_RECT(r, x, y, w, h); | ||
1107 | if (r) o->pixel_updates = eina_list_append(o->pixel_updates, r); | ||
1108 | o->changed = 1; | ||
1109 | evas_object_change(obj); | ||
1110 | } | ||
1111 | |||
1112 | EAPI void | ||
1113 | evas_object_image_alpha_set(Evas_Object *obj, Eina_Bool has_alpha) | ||
1114 | { | ||
1115 | Evas_Object_Image *o; | ||
1116 | |||
1117 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1118 | return; | ||
1119 | MAGIC_CHECK_END(); | ||
1120 | o = (Evas_Object_Image *)(obj->object_data); | ||
1121 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1122 | return; | ||
1123 | MAGIC_CHECK_END(); | ||
1124 | if ((o->preloading) && (o->engine_data)) | ||
1125 | { | ||
1126 | o->preloading = 0; | ||
1127 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
1128 | o->engine_data, | ||
1129 | obj); | ||
1130 | } | ||
1131 | if (((has_alpha) && (o->cur.has_alpha)) || | ||
1132 | ((!has_alpha) && (!o->cur.has_alpha))) | ||
1133 | return; | ||
1134 | o->cur.has_alpha = has_alpha; | ||
1135 | if (o->engine_data) | ||
1136 | { | ||
1137 | int stride = 0; | ||
1138 | |||
1139 | #ifdef EVAS_FRAME_QUEUING | ||
1140 | evas_common_pipe_op_image_flush(o->engine_data); | ||
1141 | #endif | ||
1142 | o->engine_data = obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output, | ||
1143 | o->engine_data, | ||
1144 | o->cur.has_alpha); | ||
1145 | if (obj->layer->evas->engine.func->image_scale_hint_set) | ||
1146 | obj->layer->evas->engine.func->image_scale_hint_set | ||
1147 | (obj->layer->evas->engine.data.output, | ||
1148 | o->engine_data, o->scale_hint); | ||
1149 | if (obj->layer->evas->engine.func->image_content_hint_set) | ||
1150 | obj->layer->evas->engine.func->image_content_hint_set | ||
1151 | (obj->layer->evas->engine.data.output, | ||
1152 | o->engine_data, o->content_hint); | ||
1153 | if (obj->layer->evas->engine.func->image_stride_get) | ||
1154 | obj->layer->evas->engine.func->image_stride_get | ||
1155 | (obj->layer->evas->engine.data.output, | ||
1156 | o->engine_data, &stride); | ||
1157 | else | ||
1158 | stride = o->cur.image.w * 4; | ||
1159 | o->cur.image.stride = stride; | ||
1160 | } | ||
1161 | evas_object_image_data_update_add(obj, 0, 0, o->cur.image.w, o->cur.image.h); | ||
1162 | EVAS_OBJECT_IMAGE_FREE_FILE_AND_KEY(o); | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | EAPI Eina_Bool | ||
1167 | evas_object_image_alpha_get(const Evas_Object *obj) | ||
1168 | { | ||
1169 | Evas_Object_Image *o; | ||
1170 | |||
1171 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1172 | return 0; | ||
1173 | MAGIC_CHECK_END(); | ||
1174 | o = (Evas_Object_Image *)(obj->object_data); | ||
1175 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1176 | return 0; | ||
1177 | MAGIC_CHECK_END(); | ||
1178 | return o->cur.has_alpha; | ||
1179 | } | ||
1180 | |||
1181 | EAPI void | ||
1182 | evas_object_image_smooth_scale_set(Evas_Object *obj, Eina_Bool smooth_scale) | ||
1183 | { | ||
1184 | Evas_Object_Image *o; | ||
1185 | |||
1186 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1187 | return; | ||
1188 | MAGIC_CHECK_END(); | ||
1189 | o = (Evas_Object_Image *)(obj->object_data); | ||
1190 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1191 | return; | ||
1192 | MAGIC_CHECK_END(); | ||
1193 | if (((smooth_scale) && (o->cur.smooth_scale)) || | ||
1194 | ((!smooth_scale) && (!o->cur.smooth_scale))) | ||
1195 | return; | ||
1196 | o->cur.smooth_scale = smooth_scale; | ||
1197 | o->changed = 1; | ||
1198 | evas_object_change(obj); | ||
1199 | } | ||
1200 | |||
1201 | EAPI Eina_Bool | ||
1202 | evas_object_image_smooth_scale_get(const Evas_Object *obj) | ||
1203 | { | ||
1204 | Evas_Object_Image *o; | ||
1205 | |||
1206 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1207 | return 0; | ||
1208 | MAGIC_CHECK_END(); | ||
1209 | o = (Evas_Object_Image *)(obj->object_data); | ||
1210 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1211 | return 0; | ||
1212 | MAGIC_CHECK_END(); | ||
1213 | return o->cur.smooth_scale; | ||
1214 | } | ||
1215 | |||
1216 | EAPI void | ||
1217 | evas_object_image_reload(Evas_Object *obj) | ||
1218 | { | ||
1219 | Evas_Object_Image *o; | ||
1220 | |||
1221 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1222 | return; | ||
1223 | MAGIC_CHECK_END(); | ||
1224 | o = (Evas_Object_Image *)(obj->object_data); | ||
1225 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1226 | return; | ||
1227 | MAGIC_CHECK_END(); | ||
1228 | if ((o->preloading) && (o->engine_data)) | ||
1229 | { | ||
1230 | o->preloading = 0; | ||
1231 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
1232 | o->engine_data, | ||
1233 | obj); | ||
1234 | } | ||
1235 | if ((!o->cur.file) || | ||
1236 | (o->pixels_checked_out > 0)) return; | ||
1237 | if (o->engine_data) | ||
1238 | o->engine_data = obj->layer->evas->engine.func->image_dirty_region(obj->layer->evas->engine.data.output, o->engine_data, 0, 0, o->cur.image.w, o->cur.image.h); | ||
1239 | evas_object_image_unload(obj, 1); | ||
1240 | evas_object_inform_call_image_unloaded(obj); | ||
1241 | evas_object_image_load(obj); | ||
1242 | o->prev.file = NULL; | ||
1243 | o->prev.key = NULL; | ||
1244 | o->changed = 1; | ||
1245 | evas_object_change(obj); | ||
1246 | } | ||
1247 | |||
1248 | EAPI Eina_Bool | ||
1249 | evas_object_image_save(const Evas_Object *obj, const char *file, const char *key, const char *flags) | ||
1250 | { | ||
1251 | Evas_Object_Image *o; | ||
1252 | DATA32 *data = NULL; | ||
1253 | int quality = 80, compress = 9, ok = 0; | ||
1254 | RGBA_Image *im; | ||
1255 | |||
1256 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1257 | return 0; | ||
1258 | MAGIC_CHECK_END(); | ||
1259 | o = (Evas_Object_Image *)(obj->object_data); | ||
1260 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1261 | return 0; | ||
1262 | MAGIC_CHECK_END(); | ||
1263 | |||
1264 | if (!o->engine_data) return 0; | ||
1265 | o->engine_data = obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output, | ||
1266 | o->engine_data, | ||
1267 | 0, | ||
1268 | &data, | ||
1269 | &o->load_error); | ||
1270 | if (flags) | ||
1271 | { | ||
1272 | char *p, *pp; | ||
1273 | char *tflags; | ||
1274 | |||
1275 | tflags = alloca(strlen(flags) + 1); | ||
1276 | strcpy(tflags, flags); | ||
1277 | p = tflags; | ||
1278 | while (p) | ||
1279 | { | ||
1280 | pp = strchr(p, ' '); | ||
1281 | if (pp) *pp = 0; | ||
1282 | sscanf(p, "quality=%i", &quality); | ||
1283 | sscanf(p, "compress=%i", &compress); | ||
1284 | if (pp) p = pp + 1; | ||
1285 | else break; | ||
1286 | } | ||
1287 | } | ||
1288 | im = (RGBA_Image*) evas_cache_image_data(evas_common_image_cache_get(), | ||
1289 | o->cur.image.w, | ||
1290 | o->cur.image.h, | ||
1291 | data, | ||
1292 | o->cur.has_alpha, | ||
1293 | EVAS_COLORSPACE_ARGB8888); | ||
1294 | if (im) | ||
1295 | { | ||
1296 | if (o->cur.cspace == EVAS_COLORSPACE_ARGB8888) | ||
1297 | im->image.data = data; | ||
1298 | else | ||
1299 | im->image.data = evas_object_image_data_convert_internal(o, | ||
1300 | data, | ||
1301 | EVAS_COLORSPACE_ARGB8888); | ||
1302 | if (im->image.data) | ||
1303 | { | ||
1304 | ok = evas_common_save_image_to_file(im, file, key, quality, compress); | ||
1305 | |||
1306 | if (o->cur.cspace != EVAS_COLORSPACE_ARGB8888) | ||
1307 | free(im->image.data); | ||
1308 | } | ||
1309 | |||
1310 | evas_cache_image_drop(&im->cache_entry); | ||
1311 | } | ||
1312 | return ok; | ||
1313 | } | ||
1314 | |||
1315 | EAPI Eina_Bool | ||
1316 | evas_object_image_pixels_import(Evas_Object *obj, Evas_Pixel_Import_Source *pixels) | ||
1317 | { | ||
1318 | Evas_Object_Image *o; | ||
1319 | |||
1320 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1321 | return 0; | ||
1322 | MAGIC_CHECK_END(); | ||
1323 | o = (Evas_Object_Image *)(obj->object_data); | ||
1324 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1325 | return 0; | ||
1326 | MAGIC_CHECK_END(); | ||
1327 | _evas_object_image_cleanup(obj, o); | ||
1328 | if ((pixels->w != o->cur.image.w) || (pixels->h != o->cur.image.h)) return 0; | ||
1329 | switch (pixels->format) | ||
1330 | { | ||
1331 | #if 0 | ||
1332 | case EVAS_PIXEL_FORMAT_ARGB32: | ||
1333 | { | ||
1334 | if (o->engine_data) | ||
1335 | { | ||
1336 | DATA32 *image_pixels = NULL; | ||
1337 | |||
1338 | o->engine_data = | ||
1339 | obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output, | ||
1340 | o->engine_data, | ||
1341 | 1, | ||
1342 | &image_pixels, | ||
1343 | &o->load_error); | ||
1344 | /* FIXME: need to actualyl support this */ | ||
1345 | /* memcpy(image_pixels, pixels->rows, o->cur.image.w * o->cur.image.h * 4);*/ | ||
1346 | if (o->engine_data) | ||
1347 | o->engine_data = | ||
1348 | obj->layer->evas->engine.func->image_data_put(obj->layer->evas->engine.data.output, | ||
1349 | o->engine_data, | ||
1350 | image_pixels); | ||
1351 | if (o->engine_data) | ||
1352 | o->engine_data = | ||
1353 | obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output, | ||
1354 | o->engine_data, | ||
1355 | o->cur.has_alpha); | ||
1356 | o->changed = 1; | ||
1357 | evas_object_change(obj); | ||
1358 | } | ||
1359 | } | ||
1360 | break; | ||
1361 | #endif | ||
1362 | #ifdef BUILD_CONVERT_YUV | ||
1363 | case EVAS_PIXEL_FORMAT_YUV420P_601: | ||
1364 | { | ||
1365 | if (o->engine_data) | ||
1366 | { | ||
1367 | DATA32 *image_pixels = NULL; | ||
1368 | |||
1369 | o->engine_data = | ||
1370 | obj->layer->evas->engine.func->image_data_get(obj->layer->evas->engine.data.output, | ||
1371 | o->engine_data, | ||
1372 | 1, | ||
1373 | &image_pixels, | ||
1374 | &o->load_error); | ||
1375 | if (image_pixels) | ||
1376 | evas_common_convert_yuv_420p_601_rgba((DATA8 **) pixels->rows, | ||
1377 | (DATA8 *) image_pixels, | ||
1378 | o->cur.image.w, | ||
1379 | o->cur.image.h); | ||
1380 | if (o->engine_data) | ||
1381 | o->engine_data = | ||
1382 | obj->layer->evas->engine.func->image_data_put(obj->layer->evas->engine.data.output, | ||
1383 | o->engine_data, | ||
1384 | image_pixels); | ||
1385 | if (o->engine_data) | ||
1386 | o->engine_data = | ||
1387 | obj->layer->evas->engine.func->image_alpha_set(obj->layer->evas->engine.data.output, | ||
1388 | o->engine_data, | ||
1389 | o->cur.has_alpha); | ||
1390 | o->changed = 1; | ||
1391 | evas_object_change(obj); | ||
1392 | } | ||
1393 | } | ||
1394 | break; | ||
1395 | #endif | ||
1396 | default: | ||
1397 | return 0; | ||
1398 | break; | ||
1399 | } | ||
1400 | return 1; | ||
1401 | } | ||
1402 | |||
1403 | EAPI void | ||
1404 | evas_object_image_pixels_get_callback_set(Evas_Object *obj, Evas_Object_Image_Pixels_Get_Cb func, void *data) | ||
1405 | { | ||
1406 | Evas_Object_Image *o; | ||
1407 | |||
1408 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1409 | return; | ||
1410 | MAGIC_CHECK_END(); | ||
1411 | o = (Evas_Object_Image *)(obj->object_data); | ||
1412 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1413 | return; | ||
1414 | MAGIC_CHECK_END(); | ||
1415 | o->func.get_pixels = func; | ||
1416 | o->func.get_pixels_data = data; | ||
1417 | } | ||
1418 | |||
1419 | EAPI void | ||
1420 | evas_object_image_pixels_dirty_set(Evas_Object *obj, Eina_Bool dirty) | ||
1421 | { | ||
1422 | Evas_Object_Image *o; | ||
1423 | |||
1424 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1425 | return; | ||
1426 | MAGIC_CHECK_END(); | ||
1427 | o = (Evas_Object_Image *)(obj->object_data); | ||
1428 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1429 | return; | ||
1430 | MAGIC_CHECK_END(); | ||
1431 | if (dirty) o->dirty_pixels = 1; | ||
1432 | else o->dirty_pixels = 0; | ||
1433 | o->changed = 1; | ||
1434 | evas_object_change(obj); | ||
1435 | } | ||
1436 | |||
1437 | EAPI Eina_Bool | ||
1438 | evas_object_image_pixels_dirty_get(const Evas_Object *obj) | ||
1439 | { | ||
1440 | Evas_Object_Image *o; | ||
1441 | |||
1442 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1443 | return 0; | ||
1444 | MAGIC_CHECK_END(); | ||
1445 | o = (Evas_Object_Image *)(obj->object_data); | ||
1446 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1447 | return 0; | ||
1448 | MAGIC_CHECK_END(); | ||
1449 | if (o->dirty_pixels) return 1; | ||
1450 | return 0; | ||
1451 | } | ||
1452 | |||
1453 | EAPI void | ||
1454 | evas_object_image_load_dpi_set(Evas_Object *obj, double dpi) | ||
1455 | { | ||
1456 | Evas_Object_Image *o; | ||
1457 | |||
1458 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1459 | return; | ||
1460 | MAGIC_CHECK_END(); | ||
1461 | o = (Evas_Object_Image *)(obj->object_data); | ||
1462 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1463 | return; | ||
1464 | MAGIC_CHECK_END(); | ||
1465 | if (dpi == o->load_opts.dpi) return; | ||
1466 | o->load_opts.dpi = dpi; | ||
1467 | if (o->cur.file) | ||
1468 | { | ||
1469 | evas_object_image_unload(obj, 0); | ||
1470 | evas_object_inform_call_image_unloaded(obj); | ||
1471 | evas_object_image_load(obj); | ||
1472 | o->changed = 1; | ||
1473 | evas_object_change(obj); | ||
1474 | } | ||
1475 | } | ||
1476 | |||
1477 | EAPI double | ||
1478 | evas_object_image_load_dpi_get(const Evas_Object *obj) | ||
1479 | { | ||
1480 | Evas_Object_Image *o; | ||
1481 | |||
1482 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1483 | return 0.0; | ||
1484 | MAGIC_CHECK_END(); | ||
1485 | o = (Evas_Object_Image *)(obj->object_data); | ||
1486 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1487 | return 0.0; | ||
1488 | MAGIC_CHECK_END(); | ||
1489 | return o->load_opts.dpi; | ||
1490 | } | ||
1491 | |||
1492 | EAPI void | ||
1493 | evas_object_image_load_size_set(Evas_Object *obj, int w, int h) | ||
1494 | { | ||
1495 | Evas_Object_Image *o; | ||
1496 | |||
1497 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1498 | return; | ||
1499 | MAGIC_CHECK_END(); | ||
1500 | o = (Evas_Object_Image *)(obj->object_data); | ||
1501 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1502 | return; | ||
1503 | MAGIC_CHECK_END(); | ||
1504 | if ((o->load_opts.w == w) && (o->load_opts.h == h)) return; | ||
1505 | o->load_opts.w = w; | ||
1506 | o->load_opts.h = h; | ||
1507 | if (o->cur.file) | ||
1508 | { | ||
1509 | evas_object_image_unload(obj, 0); | ||
1510 | evas_object_inform_call_image_unloaded(obj); | ||
1511 | evas_object_image_load(obj); | ||
1512 | o->changed = 1; | ||
1513 | evas_object_change(obj); | ||
1514 | } | ||
1515 | } | ||
1516 | |||
1517 | EAPI void | ||
1518 | evas_object_image_load_size_get(const Evas_Object *obj, int *w, int *h) | ||
1519 | { | ||
1520 | Evas_Object_Image *o; | ||
1521 | |||
1522 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1523 | return; | ||
1524 | MAGIC_CHECK_END(); | ||
1525 | o = (Evas_Object_Image *)(obj->object_data); | ||
1526 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1527 | return; | ||
1528 | MAGIC_CHECK_END(); | ||
1529 | if (w) *w = o->load_opts.w; | ||
1530 | if (h) *h = o->load_opts.h; | ||
1531 | } | ||
1532 | |||
1533 | EAPI void | ||
1534 | evas_object_image_load_scale_down_set(Evas_Object *obj, int scale_down) | ||
1535 | { | ||
1536 | Evas_Object_Image *o; | ||
1537 | |||
1538 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1539 | return; | ||
1540 | MAGIC_CHECK_END(); | ||
1541 | o = (Evas_Object_Image *)(obj->object_data); | ||
1542 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1543 | return; | ||
1544 | MAGIC_CHECK_END(); | ||
1545 | if (o->load_opts.scale_down_by == scale_down) return; | ||
1546 | o->load_opts.scale_down_by = scale_down; | ||
1547 | if (o->cur.file) | ||
1548 | { | ||
1549 | evas_object_image_unload(obj, 0); | ||
1550 | evas_object_inform_call_image_unloaded(obj); | ||
1551 | evas_object_image_load(obj); | ||
1552 | o->changed = 1; | ||
1553 | evas_object_change(obj); | ||
1554 | } | ||
1555 | } | ||
1556 | |||
1557 | EAPI int | ||
1558 | evas_object_image_load_scale_down_get(const Evas_Object *obj) | ||
1559 | { | ||
1560 | Evas_Object_Image *o; | ||
1561 | |||
1562 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1563 | return 0; | ||
1564 | MAGIC_CHECK_END(); | ||
1565 | o = (Evas_Object_Image *)(obj->object_data); | ||
1566 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1567 | return 0; | ||
1568 | MAGIC_CHECK_END(); | ||
1569 | return o->load_opts.scale_down_by; | ||
1570 | } | ||
1571 | |||
1572 | EAPI void | ||
1573 | evas_object_image_load_region_set(Evas_Object *obj, int x, int y, int w, int h) | ||
1574 | { | ||
1575 | Evas_Object_Image *o; | ||
1576 | |||
1577 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1578 | return; | ||
1579 | MAGIC_CHECK_END(); | ||
1580 | o = (Evas_Object_Image *)(obj->object_data); | ||
1581 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1582 | return; | ||
1583 | MAGIC_CHECK_END(); | ||
1584 | if ((o->load_opts.region.x == x) && (o->load_opts.region.y == y) && | ||
1585 | (o->load_opts.region.w == w) && (o->load_opts.region.h == h)) return; | ||
1586 | o->load_opts.region.x = x; | ||
1587 | o->load_opts.region.y = y; | ||
1588 | o->load_opts.region.w = w; | ||
1589 | o->load_opts.region.h = h; | ||
1590 | if (o->cur.file) | ||
1591 | { | ||
1592 | evas_object_image_unload(obj, 0); | ||
1593 | evas_object_inform_call_image_unloaded(obj); | ||
1594 | evas_object_image_load(obj); | ||
1595 | o->changed = 1; | ||
1596 | evas_object_change(obj); | ||
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | EAPI void | ||
1601 | evas_object_image_load_region_get(const Evas_Object *obj, int *x, int *y, int *w, int *h) | ||
1602 | { | ||
1603 | Evas_Object_Image *o; | ||
1604 | |||
1605 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1606 | return; | ||
1607 | MAGIC_CHECK_END(); | ||
1608 | o = (Evas_Object_Image *)(obj->object_data); | ||
1609 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1610 | return; | ||
1611 | MAGIC_CHECK_END(); | ||
1612 | if (x) *x = o->load_opts.region.x; | ||
1613 | if (y) *y = o->load_opts.region.y; | ||
1614 | if (w) *w = o->load_opts.region.w; | ||
1615 | if (h) *h = o->load_opts.region.h; | ||
1616 | } | ||
1617 | |||
1618 | EAPI void | ||
1619 | evas_object_image_load_orientation_set(Evas_Object *obj, Eina_Bool enable) | ||
1620 | { | ||
1621 | Evas_Object_Image *o; | ||
1622 | |||
1623 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1624 | return; | ||
1625 | MAGIC_CHECK_END(); | ||
1626 | o = (Evas_Object_Image *)(obj->object_data); | ||
1627 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1628 | return; | ||
1629 | MAGIC_CHECK_END(); | ||
1630 | o->load_opts.orientation = !!enable; | ||
1631 | } | ||
1632 | |||
1633 | EAPI Eina_Bool | ||
1634 | evas_object_image_load_orientation_get(const Evas_Object *obj) | ||
1635 | { | ||
1636 | Evas_Object_Image *o; | ||
1637 | |||
1638 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1639 | return EINA_FALSE; | ||
1640 | MAGIC_CHECK_END(); | ||
1641 | o = (Evas_Object_Image *)(obj->object_data); | ||
1642 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1643 | return EINA_FALSE; | ||
1644 | MAGIC_CHECK_END(); | ||
1645 | return o->load_opts.orientation; | ||
1646 | } | ||
1647 | |||
1648 | EAPI void | ||
1649 | evas_object_image_colorspace_set(Evas_Object *obj, Evas_Colorspace cspace) | ||
1650 | { | ||
1651 | Evas_Object_Image *o; | ||
1652 | |||
1653 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1654 | return; | ||
1655 | MAGIC_CHECK_END(); | ||
1656 | o = (Evas_Object_Image *)(obj->object_data); | ||
1657 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1658 | return; | ||
1659 | MAGIC_CHECK_END(); | ||
1660 | |||
1661 | _evas_object_image_cleanup(obj, o); | ||
1662 | #ifdef EVAS_FRAME_QUEUING | ||
1663 | if ((Evas_Colorspace)o->cur.cspace != cspace) | ||
1664 | { | ||
1665 | if (o->engine_data) | ||
1666 | evas_common_pipe_op_image_flush(o->engine_data); | ||
1667 | } | ||
1668 | #endif | ||
1669 | |||
1670 | o->cur.cspace = cspace; | ||
1671 | if (o->engine_data) | ||
1672 | obj->layer->evas->engine.func->image_colorspace_set(obj->layer->evas->engine.data.output, | ||
1673 | o->engine_data, | ||
1674 | cspace); | ||
1675 | } | ||
1676 | |||
1677 | EAPI Evas_Colorspace | ||
1678 | evas_object_image_colorspace_get(const Evas_Object *obj) | ||
1679 | { | ||
1680 | Evas_Object_Image *o; | ||
1681 | |||
1682 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1683 | return EVAS_COLORSPACE_ARGB8888; | ||
1684 | MAGIC_CHECK_END(); | ||
1685 | o = (Evas_Object_Image *)(obj->object_data); | ||
1686 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1687 | return EVAS_COLORSPACE_ARGB8888; | ||
1688 | MAGIC_CHECK_END(); | ||
1689 | return o->cur.cspace; | ||
1690 | } | ||
1691 | |||
1692 | EAPI void | ||
1693 | evas_object_image_video_surface_set(Evas_Object *obj, Evas_Video_Surface *surf) | ||
1694 | { | ||
1695 | Evas_Object_Image *o; | ||
1696 | |||
1697 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1698 | return; | ||
1699 | MAGIC_CHECK_END(); | ||
1700 | o = (Evas_Object_Image *)(obj->object_data); | ||
1701 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1702 | return; | ||
1703 | MAGIC_CHECK_END(); | ||
1704 | _evas_object_image_cleanup(obj, o); | ||
1705 | if (o->video_surface) | ||
1706 | { | ||
1707 | o->video_surface = 0; | ||
1708 | obj->layer->evas->video_objects = eina_list_remove(obj->layer->evas->video_objects, obj); | ||
1709 | } | ||
1710 | |||
1711 | if (surf) | ||
1712 | { | ||
1713 | if (surf->version != EVAS_VIDEO_SURFACE_VERSION) return ; | ||
1714 | |||
1715 | if (!surf->update_pixels || | ||
1716 | !surf->move || | ||
1717 | !surf->resize || | ||
1718 | !surf->hide || | ||
1719 | !surf->show) | ||
1720 | return ; | ||
1721 | |||
1722 | o->created = EINA_TRUE; | ||
1723 | o->video_surface = 1; | ||
1724 | o->video = *surf; | ||
1725 | |||
1726 | obj->layer->evas->video_objects = eina_list_append(obj->layer->evas->video_objects, obj); | ||
1727 | } | ||
1728 | else | ||
1729 | { | ||
1730 | o->video_surface = 0; | ||
1731 | o->video.update_pixels = NULL; | ||
1732 | o->video.move = NULL; | ||
1733 | o->video.resize = NULL; | ||
1734 | o->video.hide = NULL; | ||
1735 | o->video.show = NULL; | ||
1736 | o->video.data = NULL; | ||
1737 | } | ||
1738 | } | ||
1739 | |||
1740 | EAPI const Evas_Video_Surface * | ||
1741 | evas_object_image_video_surface_get(const Evas_Object *obj) | ||
1742 | { | ||
1743 | Evas_Object_Image *o; | ||
1744 | |||
1745 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1746 | return NULL; | ||
1747 | MAGIC_CHECK_END(); | ||
1748 | o = (Evas_Object_Image *)(obj->object_data); | ||
1749 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1750 | return NULL; | ||
1751 | MAGIC_CHECK_END(); | ||
1752 | if (!o->video_surface) return NULL; | ||
1753 | return &o->video; | ||
1754 | } | ||
1755 | |||
1756 | EAPI void | ||
1757 | evas_object_image_native_surface_set(Evas_Object *obj, Evas_Native_Surface *surf) | ||
1758 | { | ||
1759 | Evas_Object_Image *o; | ||
1760 | |||
1761 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1762 | return; | ||
1763 | MAGIC_CHECK_END(); | ||
1764 | o = (Evas_Object_Image *)(obj->object_data); | ||
1765 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1766 | return; | ||
1767 | MAGIC_CHECK_END(); | ||
1768 | _evas_object_image_cleanup(obj, o); | ||
1769 | if (!obj->layer->evas->engine.func->image_native_set) return; | ||
1770 | if ((surf) && | ||
1771 | ((surf->version < 2) || | ||
1772 | (surf->version > EVAS_NATIVE_SURFACE_VERSION))) return; | ||
1773 | o->engine_data = | ||
1774 | obj->layer->evas->engine.func->image_native_set(obj->layer->evas->engine.data.output, | ||
1775 | o->engine_data, | ||
1776 | surf); | ||
1777 | } | ||
1778 | |||
1779 | EAPI Evas_Native_Surface * | ||
1780 | evas_object_image_native_surface_get(const Evas_Object *obj) | ||
1781 | { | ||
1782 | Evas_Object_Image *o; | ||
1783 | |||
1784 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1785 | return NULL; | ||
1786 | MAGIC_CHECK_END(); | ||
1787 | o = (Evas_Object_Image *)(obj->object_data); | ||
1788 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1789 | return NULL; | ||
1790 | MAGIC_CHECK_END(); | ||
1791 | if (!obj->layer->evas->engine.func->image_native_get) return NULL; | ||
1792 | return obj->layer->evas->engine.func->image_native_get(obj->layer->evas->engine.data.output, | ||
1793 | o->engine_data); | ||
1794 | } | ||
1795 | |||
1796 | EAPI void | ||
1797 | evas_object_image_scale_hint_set(Evas_Object *obj, Evas_Image_Scale_Hint hint) | ||
1798 | { | ||
1799 | Evas_Object_Image *o; | ||
1800 | |||
1801 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1802 | return; | ||
1803 | MAGIC_CHECK_END(); | ||
1804 | o = (Evas_Object_Image *)(obj->object_data); | ||
1805 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1806 | return; | ||
1807 | MAGIC_CHECK_END(); | ||
1808 | if (o->scale_hint == hint) return; | ||
1809 | #ifdef EVAS_FRAME_QUEUING | ||
1810 | if (o->engine_data) | ||
1811 | evas_common_pipe_op_image_flush(o->engine_data); | ||
1812 | #endif | ||
1813 | o->scale_hint = hint; | ||
1814 | if (o->engine_data) | ||
1815 | { | ||
1816 | int stride = 0; | ||
1817 | |||
1818 | if (obj->layer->evas->engine.func->image_scale_hint_set) | ||
1819 | obj->layer->evas->engine.func->image_scale_hint_set | ||
1820 | (obj->layer->evas->engine.data.output, | ||
1821 | o->engine_data, o->scale_hint); | ||
1822 | if (obj->layer->evas->engine.func->image_stride_get) | ||
1823 | obj->layer->evas->engine.func->image_stride_get | ||
1824 | (obj->layer->evas->engine.data.output, | ||
1825 | o->engine_data, &stride); | ||
1826 | else | ||
1827 | stride = o->cur.image.w * 4; | ||
1828 | o->cur.image.stride = stride; | ||
1829 | } | ||
1830 | } | ||
1831 | |||
1832 | EAPI Evas_Image_Scale_Hint | ||
1833 | evas_object_image_scale_hint_get(const Evas_Object *obj) | ||
1834 | { | ||
1835 | Evas_Object_Image *o; | ||
1836 | |||
1837 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1838 | return EVAS_IMAGE_SCALE_HINT_NONE; | ||
1839 | MAGIC_CHECK_END(); | ||
1840 | o = (Evas_Object_Image *)(obj->object_data); | ||
1841 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1842 | return EVAS_IMAGE_SCALE_HINT_NONE; | ||
1843 | MAGIC_CHECK_END(); | ||
1844 | return o->scale_hint; | ||
1845 | } | ||
1846 | |||
1847 | EAPI void | ||
1848 | evas_object_image_content_hint_set(Evas_Object *obj, Evas_Image_Content_Hint hint) | ||
1849 | { | ||
1850 | Evas_Object_Image *o; | ||
1851 | |||
1852 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1853 | return; | ||
1854 | MAGIC_CHECK_END(); | ||
1855 | o = (Evas_Object_Image *)(obj->object_data); | ||
1856 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1857 | return; | ||
1858 | MAGIC_CHECK_END(); | ||
1859 | if (o->content_hint == hint) return; | ||
1860 | #ifdef EVAS_FRAME_QUEUING | ||
1861 | if (o->engine_data) | ||
1862 | evas_common_pipe_op_image_flush(o->engine_data); | ||
1863 | #endif | ||
1864 | o->content_hint = hint; | ||
1865 | if (o->engine_data) | ||
1866 | { | ||
1867 | int stride = 0; | ||
1868 | |||
1869 | if (obj->layer->evas->engine.func->image_content_hint_set) | ||
1870 | obj->layer->evas->engine.func->image_content_hint_set | ||
1871 | (obj->layer->evas->engine.data.output, | ||
1872 | o->engine_data, o->content_hint); | ||
1873 | if (obj->layer->evas->engine.func->image_stride_get) | ||
1874 | obj->layer->evas->engine.func->image_stride_get | ||
1875 | (obj->layer->evas->engine.data.output, | ||
1876 | o->engine_data, &stride); | ||
1877 | else | ||
1878 | stride = o->cur.image.w * 4; | ||
1879 | o->cur.image.stride = stride; | ||
1880 | } | ||
1881 | } | ||
1882 | |||
1883 | EAPI void | ||
1884 | evas_object_image_alpha_mask_set(Evas_Object *obj, Eina_Bool ismask) | ||
1885 | { | ||
1886 | Evas_Object_Image *o; | ||
1887 | |||
1888 | if (!ismask) return; | ||
1889 | |||
1890 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1891 | return; | ||
1892 | MAGIC_CHECK_END(); | ||
1893 | o = (Evas_Object_Image *)(obj->object_data); | ||
1894 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1895 | return; | ||
1896 | MAGIC_CHECK_END(); | ||
1897 | |||
1898 | /* Convert to A8 if not already */ | ||
1899 | |||
1900 | /* done */ | ||
1901 | |||
1902 | } | ||
1903 | |||
1904 | #define FRAME_MAX 1024 | ||
1905 | EAPI Evas_Image_Content_Hint | ||
1906 | evas_object_image_content_hint_get(const Evas_Object *obj) | ||
1907 | { | ||
1908 | Evas_Object_Image *o; | ||
1909 | |||
1910 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1911 | return EVAS_IMAGE_CONTENT_HINT_NONE; | ||
1912 | MAGIC_CHECK_END(); | ||
1913 | o = (Evas_Object_Image *)(obj->object_data); | ||
1914 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1915 | return EVAS_IMAGE_CONTENT_HINT_NONE; | ||
1916 | MAGIC_CHECK_END(); | ||
1917 | return o->content_hint; | ||
1918 | } | ||
1919 | |||
1920 | /* animated feature */ | ||
1921 | EAPI Eina_Bool | ||
1922 | evas_object_image_animated_get(const Evas_Object *obj) | ||
1923 | { | ||
1924 | Evas_Object_Image *o; | ||
1925 | |||
1926 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1927 | return EINA_FALSE; | ||
1928 | MAGIC_CHECK_END(); | ||
1929 | o = (Evas_Object_Image *)(obj->object_data); | ||
1930 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1931 | return EINA_FALSE; | ||
1932 | MAGIC_CHECK_END(); | ||
1933 | |||
1934 | if (obj->layer->evas->engine.func->image_animated_get) | ||
1935 | return obj->layer->evas->engine.func->image_animated_get(obj->layer->evas->engine.data.output, o->engine_data); | ||
1936 | return EINA_FALSE; | ||
1937 | } | ||
1938 | |||
1939 | EAPI int | ||
1940 | evas_object_image_animated_frame_count_get(const Evas_Object *obj) | ||
1941 | { | ||
1942 | Evas_Object_Image *o; | ||
1943 | |||
1944 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1945 | return -1; | ||
1946 | MAGIC_CHECK_END(); | ||
1947 | o = (Evas_Object_Image *)(obj->object_data); | ||
1948 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1949 | return -1; | ||
1950 | MAGIC_CHECK_END(); | ||
1951 | |||
1952 | if (!evas_object_image_animated_get(obj)) return -1; | ||
1953 | if (obj->layer->evas->engine.func->image_animated_frame_count_get) | ||
1954 | return obj->layer->evas->engine.func->image_animated_frame_count_get(obj->layer->evas->engine.data.output, o->engine_data); | ||
1955 | return -1; | ||
1956 | } | ||
1957 | |||
1958 | EAPI Evas_Image_Animated_Loop_Hint | ||
1959 | evas_object_image_animated_loop_type_get(const Evas_Object *obj) | ||
1960 | { | ||
1961 | Evas_Object_Image *o; | ||
1962 | |||
1963 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1964 | return EVAS_IMAGE_ANIMATED_HINT_NONE; | ||
1965 | MAGIC_CHECK_END(); | ||
1966 | o = (Evas_Object_Image *)(obj->object_data); | ||
1967 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1968 | return EVAS_IMAGE_ANIMATED_HINT_NONE; | ||
1969 | MAGIC_CHECK_END(); | ||
1970 | |||
1971 | if (!evas_object_image_animated_get(obj)) return EVAS_IMAGE_ANIMATED_HINT_NONE; | ||
1972 | |||
1973 | if (obj->layer->evas->engine.func->image_animated_loop_type_get) | ||
1974 | return obj->layer->evas->engine.func->image_animated_loop_type_get(obj->layer->evas->engine.data.output, o->engine_data); | ||
1975 | return EVAS_IMAGE_ANIMATED_HINT_NONE; | ||
1976 | } | ||
1977 | |||
1978 | EAPI int | ||
1979 | evas_object_image_animated_loop_count_get(const Evas_Object *obj) | ||
1980 | { | ||
1981 | Evas_Object_Image *o; | ||
1982 | |||
1983 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1984 | return -1; | ||
1985 | MAGIC_CHECK_END(); | ||
1986 | o = (Evas_Object_Image *)(obj->object_data); | ||
1987 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
1988 | return -1; | ||
1989 | MAGIC_CHECK_END(); | ||
1990 | |||
1991 | if (!evas_object_image_animated_get(obj)) return -1; | ||
1992 | |||
1993 | if (obj->layer->evas->engine.func->image_animated_loop_count_get) | ||
1994 | return obj->layer->evas->engine.func->image_animated_loop_count_get(obj->layer->evas->engine.data.output, o->engine_data); | ||
1995 | return -1; | ||
1996 | } | ||
1997 | |||
1998 | EAPI double | ||
1999 | evas_object_image_animated_frame_duration_get(const Evas_Object *obj, int start_frame, int frame_num) | ||
2000 | { | ||
2001 | Evas_Object_Image *o; | ||
2002 | int frame_count = 0; | ||
2003 | |||
2004 | if (start_frame < 1) return -1; | ||
2005 | if (frame_num < 0) return -1; | ||
2006 | |||
2007 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
2008 | return -1; | ||
2009 | MAGIC_CHECK_END(); | ||
2010 | o = (Evas_Object_Image *)(obj->object_data); | ||
2011 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
2012 | return -1; | ||
2013 | MAGIC_CHECK_END(); | ||
2014 | |||
2015 | if (!evas_object_image_animated_get(obj)) return -1; | ||
2016 | |||
2017 | if (!obj->layer->evas->engine.func->image_animated_frame_count_get) return -1; | ||
2018 | |||
2019 | frame_count = obj->layer->evas->engine.func->image_animated_frame_count_get(obj->layer->evas->engine.data.output, o->engine_data); | ||
2020 | |||
2021 | if ((start_frame + frame_num) > frame_count) return -1; | ||
2022 | if (obj->layer->evas->engine.func->image_animated_frame_duration_get) | ||
2023 | return obj->layer->evas->engine.func->image_animated_frame_duration_get(obj->layer->evas->engine.data.output, o->engine_data, start_frame, frame_num); | ||
2024 | return -1; | ||
2025 | } | ||
2026 | |||
2027 | EAPI void | ||
2028 | evas_object_image_animated_frame_set(Evas_Object *obj, int frame_index) | ||
2029 | { | ||
2030 | Evas_Object_Image *o; | ||
2031 | int frame_count = 0; | ||
2032 | |||
2033 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
2034 | return; | ||
2035 | MAGIC_CHECK_END(); | ||
2036 | o = (Evas_Object_Image *)(obj->object_data); | ||
2037 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
2038 | return; | ||
2039 | MAGIC_CHECK_END(); | ||
2040 | |||
2041 | if (!o->cur.file) return; | ||
2042 | if (o->cur.frame == frame_index) return; | ||
2043 | |||
2044 | if (!evas_object_image_animated_get(obj)) return; | ||
2045 | |||
2046 | frame_count = evas_object_image_animated_frame_count_get(obj); | ||
2047 | |||
2048 | /* limit the size of frame to FRAME_MAX */ | ||
2049 | if ((frame_count > FRAME_MAX) || (frame_count < 0) || (frame_index > frame_count)) | ||
2050 | return; | ||
2051 | |||
2052 | if (!obj->layer->evas->engine.func->image_animated_frame_set) return; | ||
2053 | if (!obj->layer->evas->engine.func->image_animated_frame_set(obj->layer->evas->engine.data.output, o->engine_data, frame_index)) | ||
2054 | return; | ||
2055 | |||
2056 | o->prev.frame = o->cur.frame; | ||
2057 | o->cur.frame = frame_index; | ||
2058 | |||
2059 | o->changed = 1; | ||
2060 | evas_object_change(obj); | ||
2061 | |||
2062 | } | ||
2063 | |||
2064 | EAPI void | ||
2065 | evas_image_cache_flush(Evas *e) | ||
2066 | { | ||
2067 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
2068 | return; | ||
2069 | MAGIC_CHECK_END(); | ||
2070 | |||
2071 | e->engine.func->image_cache_flush(e->engine.data.output); | ||
2072 | } | ||
2073 | |||
2074 | EAPI void | ||
2075 | evas_image_cache_reload(Evas *e) | ||
2076 | { | ||
2077 | Evas_Layer *layer; | ||
2078 | |||
2079 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
2080 | return; | ||
2081 | MAGIC_CHECK_END(); | ||
2082 | |||
2083 | evas_image_cache_flush(e); | ||
2084 | EINA_INLIST_FOREACH(e->layers, layer) | ||
2085 | { | ||
2086 | Evas_Object *obj; | ||
2087 | |||
2088 | EINA_INLIST_FOREACH(layer->objects, obj) | ||
2089 | { | ||
2090 | Evas_Object_Image *o; | ||
2091 | |||
2092 | o = (Evas_Object_Image *)(obj->object_data); | ||
2093 | if (o->magic == MAGIC_OBJ_IMAGE) | ||
2094 | { | ||
2095 | evas_object_image_unload(obj, 1); | ||
2096 | evas_object_inform_call_image_unloaded(obj); | ||
2097 | } | ||
2098 | } | ||
2099 | } | ||
2100 | evas_image_cache_flush(e); | ||
2101 | EINA_INLIST_FOREACH(e->layers, layer) | ||
2102 | { | ||
2103 | Evas_Object *obj; | ||
2104 | |||
2105 | EINA_INLIST_FOREACH(layer->objects, obj) | ||
2106 | { | ||
2107 | Evas_Object_Image *o; | ||
2108 | |||
2109 | o = (Evas_Object_Image *)(obj->object_data); | ||
2110 | if (o->magic == MAGIC_OBJ_IMAGE) | ||
2111 | { | ||
2112 | evas_object_image_load(obj); | ||
2113 | o->changed = 1; | ||
2114 | evas_object_change(obj); | ||
2115 | } | ||
2116 | } | ||
2117 | } | ||
2118 | evas_image_cache_flush(e); | ||
2119 | } | ||
2120 | |||
2121 | EAPI void | ||
2122 | evas_image_cache_set(Evas *e, int size) | ||
2123 | { | ||
2124 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
2125 | return; | ||
2126 | MAGIC_CHECK_END(); | ||
2127 | |||
2128 | if (size < 0) size = 0; | ||
2129 | e->engine.func->image_cache_set(e->engine.data.output, size); | ||
2130 | } | ||
2131 | |||
2132 | EAPI int | ||
2133 | evas_image_cache_get(const Evas *e) | ||
2134 | { | ||
2135 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
2136 | return 0; | ||
2137 | MAGIC_CHECK_END(); | ||
2138 | |||
2139 | return e->engine.func->image_cache_get(e->engine.data.output); | ||
2140 | } | ||
2141 | |||
2142 | EAPI Eina_Bool | ||
2143 | evas_image_max_size_get(const Evas *e, int *maxw, int *maxh) | ||
2144 | { | ||
2145 | int w = 0, h = 0; | ||
2146 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
2147 | return EINA_FALSE; | ||
2148 | MAGIC_CHECK_END(); | ||
2149 | |||
2150 | if (maxw) *maxw = 0xffff; | ||
2151 | if (maxh) *maxh = 0xffff; | ||
2152 | if (!e->engine.func->image_max_size_get) return EINA_FALSE; | ||
2153 | e->engine.func->image_max_size_get(e->engine.data.output, &w, &h); | ||
2154 | if (maxw) *maxw = w; | ||
2155 | if (maxh) *maxh = h; | ||
2156 | return EINA_TRUE; | ||
2157 | } | ||
2158 | |||
2159 | /* all nice and private */ | ||
2160 | static void | ||
2161 | _proxy_unset(Evas_Object *proxy) | ||
2162 | { | ||
2163 | Evas_Object_Image *o; | ||
2164 | |||
2165 | o = proxy->object_data; | ||
2166 | if (!o->cur.source) return; | ||
2167 | |||
2168 | o->cur.source->proxy.proxies = eina_list_remove(o->cur.source->proxy.proxies, proxy); | ||
2169 | |||
2170 | o->cur.source = NULL; | ||
2171 | if (o->cur.defmap) | ||
2172 | { | ||
2173 | evas_map_free(o->cur.defmap); | ||
2174 | o->cur.defmap = NULL; | ||
2175 | } | ||
2176 | } | ||
2177 | |||
2178 | |||
2179 | static void | ||
2180 | _proxy_set(Evas_Object *proxy, Evas_Object *src) | ||
2181 | { | ||
2182 | Evas_Object_Image *o; | ||
2183 | |||
2184 | o = proxy->object_data; | ||
2185 | |||
2186 | evas_object_image_file_set(proxy, NULL, NULL); | ||
2187 | |||
2188 | o->cur.source = src; | ||
2189 | |||
2190 | src->proxy.proxies = eina_list_append(src->proxy.proxies, proxy); | ||
2191 | src->proxy.redraw = EINA_TRUE; | ||
2192 | } | ||
2193 | |||
2194 | /* Some moron just set a proxy on a proxy. | ||
2195 | * Give them some pixels. A random color | ||
2196 | */ | ||
2197 | static void | ||
2198 | _proxy_error(Evas_Object *proxy, void *context, void *output, void *surface, | ||
2199 | int x, int y) | ||
2200 | { | ||
2201 | Evas_Func *func; | ||
2202 | int r = rand() % 255; | ||
2203 | int g = rand() % 255; | ||
2204 | int b = rand() % 255; | ||
2205 | |||
2206 | /* XXX: Eina log error or something I'm sure | ||
2207 | * If it bugs you, just fix it. Don't tell me */ | ||
2208 | if (VERBOSE_PROXY_ERROR) printf("Err: Argh! Recursive proxies.\n"); | ||
2209 | |||
2210 | func = proxy->layer->evas->engine.func; | ||
2211 | func->context_color_set(output, context, r, g, b, 255); | ||
2212 | func->context_multiplier_unset(output, context); | ||
2213 | func->context_render_op_set(output, context, proxy->cur.render_op); | ||
2214 | func->rectangle_draw(output, context, surface, proxy->cur.geometry.x + x, | ||
2215 | proxy->cur.geometry.y + y, | ||
2216 | proxy->cur.geometry.w, | ||
2217 | proxy->cur.geometry.h); | ||
2218 | return; | ||
2219 | } | ||
2220 | |||
2221 | /* | ||
2222 | static void | ||
2223 | _proxy_subrender_recurse(Evas_Object *obj, Evas_Object *clip, void *output, void *surface, void *ctx, int x, int y) | ||
2224 | { | ||
2225 | Evas_Object *obj2; | ||
2226 | Evas *e = obj->layer->evas; | ||
2227 | |||
2228 | if (obj->clip.clipees) return; | ||
2229 | if (!obj->cur.visible) return; | ||
2230 | if ((!clip) || (clip != obj->cur.clipper)) | ||
2231 | { | ||
2232 | if (!obj->cur.cache.clip.visible) return; | ||
2233 | if ((obj->cur.cache.clip.a == 0) && | ||
2234 | (obj->cur.render_op == EVAS_RENDER_BLEND)) return; | ||
2235 | } | ||
2236 | if ((obj->func->is_visible) && (!obj->func->is_visible(obj))) return; | ||
2237 | |||
2238 | if (!obj->pre_render_done) | ||
2239 | obj->func->render_pre(obj); | ||
2240 | ctx = e->engine.func->context_new(output); | ||
2241 | if (obj->smart.smart) | ||
2242 | { | ||
2243 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2) | ||
2244 | { | ||
2245 | _proxy_subrender_recurse(obj2, clip, output, surface, ctx, x, y); | ||
2246 | } | ||
2247 | } | ||
2248 | else | ||
2249 | { | ||
2250 | obj->func->render(obj, output, ctx, surface, x, y); | ||
2251 | } | ||
2252 | e->engine.func->context_free(output, ctx); | ||
2253 | } | ||
2254 | */ | ||
2255 | |||
2256 | /** | ||
2257 | * Render the source object when a proxy is set. | ||
2258 | * | ||
2259 | * Used to force a draw if necessary, else just makes sures it's available. | ||
2260 | */ | ||
2261 | static void | ||
2262 | _proxy_subrender(Evas *e, Evas_Object *source) | ||
2263 | { | ||
2264 | void *ctx; | ||
2265 | /* Evas_Object *obj2, *clip;*/ | ||
2266 | int w, h; | ||
2267 | |||
2268 | if (!source) return; | ||
2269 | |||
2270 | w = source->cur.geometry.w; | ||
2271 | h = source->cur.geometry.h; | ||
2272 | |||
2273 | source->proxy.redraw = EINA_FALSE; | ||
2274 | |||
2275 | /* We need to redraw surface then */ | ||
2276 | if ((source->proxy.surface) && | ||
2277 | ((source->proxy.w != w) || (source->proxy.h != h))) | ||
2278 | { | ||
2279 | e->engine.func->image_map_surface_free(e->engine.data.output, | ||
2280 | source->proxy.surface); | ||
2281 | source->proxy.surface = NULL; | ||
2282 | } | ||
2283 | |||
2284 | /* FIXME: Hardcoded alpha 'on' */ | ||
2285 | /* FIXME (cont): Should see if the object has alpha */ | ||
2286 | if (!source->proxy.surface) | ||
2287 | { | ||
2288 | source->proxy.surface = e->engine.func->image_map_surface_new | ||
2289 | (e->engine.data.output, w, h, 1); | ||
2290 | source->proxy.w = w; | ||
2291 | source->proxy.h = h; | ||
2292 | } | ||
2293 | |||
2294 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
2295 | e->engine.func->context_color_set(e->engine.data.output, ctx, 0, 0, 0, 0); | ||
2296 | e->engine.func->context_render_op_set(e->engine.data.output, ctx, EVAS_RENDER_COPY); | ||
2297 | e->engine.func->rectangle_draw(e->engine.data.output, ctx, | ||
2298 | source->proxy.surface, 0, 0, w, h); | ||
2299 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
2300 | |||
2301 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
2302 | evas_render_mapped(e, source, ctx, source->proxy.surface, | ||
2303 | -source->cur.geometry.x, | ||
2304 | -source->cur.geometry.y, | ||
2305 | 1, 0, 0, e->output.w, e->output.h); | ||
2306 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
2307 | source->proxy.surface = e->engine.func->image_dirty_region | ||
2308 | (e->engine.data.output, source->proxy.surface, 0, 0, w, h); | ||
2309 | /* | ||
2310 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
2311 | if (source->smart.smart) | ||
2312 | { | ||
2313 | clip = evas_object_smart_clipped_clipper_get(source); | ||
2314 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(source), obj2) | ||
2315 | { | ||
2316 | _proxy_subrender_recurse(obj2, clip, e->engine.data.output, | ||
2317 | source->proxy.surface, | ||
2318 | ctx, | ||
2319 | -source->cur.geometry.x, | ||
2320 | -source->cur.geometry.y); | ||
2321 | } | ||
2322 | } | ||
2323 | else | ||
2324 | { | ||
2325 | if (!source->pre_render_done) | ||
2326 | source->func->render_pre(source); | ||
2327 | source->func->render(source, e->engine.data.output, ctx, | ||
2328 | source->proxy.surface, | ||
2329 | -source->cur.geometry.x, | ||
2330 | -source->cur.geometry.y); | ||
2331 | } | ||
2332 | |||
2333 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
2334 | source->proxy.surface = e->engine.func->image_dirty_region | ||
2335 | (e->engine.data.output, source->proxy.surface, 0, 0, w, h); | ||
2336 | */ | ||
2337 | } | ||
2338 | |||
2339 | #if 0 // filtering disabled | ||
2340 | /* | ||
2341 | * | ||
2342 | * Note that this is similar to proxy_subrender_recurse. It should be | ||
2343 | * possible to merge I guess | ||
2344 | */ | ||
2345 | static void | ||
2346 | image_filter_draw_under_recurse(Evas *e, Evas_Object *obj, Evas_Object *stop, | ||
2347 | void *output, void *ctx, void *surface, | ||
2348 | int x, int y) | ||
2349 | { | ||
2350 | Evas_Object *obj2; | ||
2351 | |||
2352 | if (obj->clip.clipees) return; | ||
2353 | /* FIXME: Doing bounding box test */ | ||
2354 | if (!evas_object_is_in_output_rect(obj, stop->cur.geometry.x, | ||
2355 | stop->cur.geometry.y, | ||
2356 | stop->cur.geometry.w, | ||
2357 | stop->cur.geometry.h)) | ||
2358 | return; | ||
2359 | |||
2360 | if (!evas_object_is_visible(obj)) return; | ||
2361 | obj->pre_render_done = 1; | ||
2362 | ctx = e->engine.func->context_new(output); | ||
2363 | |||
2364 | if (obj->smart.smart) | ||
2365 | { | ||
2366 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2) | ||
2367 | { | ||
2368 | if (obj2 == stop) return; | ||
2369 | image_filter_draw_under_recurse(e, obj2, stop, output, surface, | ||
2370 | ctx, x, y); | ||
2371 | } | ||
2372 | } | ||
2373 | else | ||
2374 | obj->func->render(obj, output, ctx, surface, x ,y); | ||
2375 | e->engine.func->context_free(output, ctx); | ||
2376 | } | ||
2377 | |||
2378 | /* | ||
2379 | * Draw all visible objects intersecting an object which are _beneath_ it. | ||
2380 | */ | ||
2381 | static void | ||
2382 | image_filter_draw_under(Evas *e, Evas_Object *stop, void *output, void *ctx, void *surface, int dx, int dy) | ||
2383 | { | ||
2384 | Evas_Layer *lay; | ||
2385 | int x, y; | ||
2386 | |||
2387 | x = stop->cur.geometry.x - dx; | ||
2388 | y = stop->cur.geometry.y - dy; | ||
2389 | |||
2390 | EINA_INLIST_FOREACH(e->layers, lay) | ||
2391 | { | ||
2392 | Evas_Object *obj; | ||
2393 | EINA_INLIST_FOREACH(lay->objects, obj) | ||
2394 | { | ||
2395 | if (obj->delete_me) continue; | ||
2396 | if (obj == stop) return; | ||
2397 | /* FIXME: Do bounding box check */ | ||
2398 | image_filter_draw_under_recurse(e, obj, stop, output, ctx, | ||
2399 | surface, -x, -y); | ||
2400 | } | ||
2401 | } | ||
2402 | e->engine.func->image_dirty_region(output, surface, 0, 0, 300, 300); | ||
2403 | e->engine.func->output_flush(output); | ||
2404 | } | ||
2405 | |||
2406 | /* | ||
2407 | * Update the filtered object. | ||
2408 | * | ||
2409 | * Creates a new context, and renders stuff (filtered) onto that. | ||
2410 | */ | ||
2411 | Filtered_Image * | ||
2412 | image_filter_update(Evas *e, Evas_Object *obj, void *src, int imagew, int imageh, int *outw, int *outh) | ||
2413 | { | ||
2414 | int w, h; | ||
2415 | void *ctx; | ||
2416 | Evas_Filter_Info *info; | ||
2417 | void *surface; | ||
2418 | Eina_Bool alpha; | ||
2419 | |||
2420 | info = obj->filter; | ||
2421 | |||
2422 | if (info->mode == EVAS_FILTER_MODE_BELOW) | ||
2423 | { | ||
2424 | w = obj->cur.geometry.w; | ||
2425 | h = obj->cur.geometry.h; | ||
2426 | evas_filter_get_size(info, w, h, &imagew, &imageh, EINA_TRUE); | ||
2427 | alpha = EINA_FALSE; | ||
2428 | } | ||
2429 | else | ||
2430 | { | ||
2431 | evas_filter_get_size(info, imagew, imageh, &w, &h, EINA_FALSE); | ||
2432 | alpha = e->engine.func->image_alpha_get(e->engine.data.output, src); | ||
2433 | } | ||
2434 | |||
2435 | /* Certain filters may make alpha images anyway */ | ||
2436 | if (alpha == EINA_FALSE) alpha = evas_filter_always_alpha(info); | ||
2437 | |||
2438 | surface = e->engine.func->image_map_surface_new(e->engine.data.output, w, h, | ||
2439 | alpha); | ||
2440 | |||
2441 | if (info->mode == EVAS_FILTER_MODE_BELOW) | ||
2442 | { | ||
2443 | void *subsurface; | ||
2444 | int disw, dish; | ||
2445 | int dx, dy; | ||
2446 | disw = obj->cur.geometry.w; | ||
2447 | dish = obj->cur.geometry.h; | ||
2448 | dx = (imagew - w) >> 1; | ||
2449 | dy = (imageh - h) >> 1; | ||
2450 | subsurface = e->engine.func->image_map_surface_new | ||
2451 | (e->engine.data.output, imagew, imageh, 1); | ||
2452 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
2453 | e->engine.func->context_color_set(e->engine.data.output, ctx, 0, 255, 0, 255); | ||
2454 | e->engine.func->context_render_op_set(e->engine.data.output, ctx, EVAS_RENDER_COPY); | ||
2455 | e->engine.func->rectangle_draw(e->engine.data.output, ctx, | ||
2456 | subsurface, 0, 0, imagew, imageh); | ||
2457 | |||
2458 | image_filter_draw_under(e, obj, e->engine.data.output, ctx, | ||
2459 | subsurface, dx, dy); | ||
2460 | |||
2461 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
2462 | |||
2463 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
2464 | |||
2465 | e->engine.func->image_draw_filtered(e->engine.data.output, | ||
2466 | ctx, surface, subsurface, info); | ||
2467 | |||
2468 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
2469 | |||
2470 | e->engine.func->image_map_surface_free(e->engine.data.output, | ||
2471 | subsurface); | ||
2472 | } | ||
2473 | else | ||
2474 | { | ||
2475 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
2476 | e->engine.func->image_draw_filtered(e->engine.data.output, | ||
2477 | ctx, surface, src, info); | ||
2478 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
2479 | } | ||
2480 | |||
2481 | e->engine.func->image_dirty_region(e->engine.data.output, surface, | ||
2482 | 0, 0, w, h); | ||
2483 | if (outw) *outw = w; | ||
2484 | if (outh) *outh = h; | ||
2485 | return e->engine.func->image_filtered_save(src, surface, | ||
2486 | obj->filter->key, | ||
2487 | obj->filter->len); | ||
2488 | } | ||
2489 | #endif | ||
2490 | |||
2491 | static void | ||
2492 | evas_object_image_unload(Evas_Object *obj, Eina_Bool dirty) | ||
2493 | { | ||
2494 | Evas_Object_Image *o; | ||
2495 | |||
2496 | o = (Evas_Object_Image *)(obj->object_data); | ||
2497 | |||
2498 | if ((!o->cur.file) || | ||
2499 | (o->pixels_checked_out > 0)) return; | ||
2500 | if (dirty) | ||
2501 | { | ||
2502 | if (o->engine_data) | ||
2503 | o->engine_data = obj->layer->evas->engine.func->image_dirty_region | ||
2504 | (obj->layer->evas->engine.data.output, | ||
2505 | o->engine_data, | ||
2506 | 0, 0, | ||
2507 | o->cur.image.w, o->cur.image.h); | ||
2508 | } | ||
2509 | if (o->engine_data) | ||
2510 | { | ||
2511 | if (o->preloading) | ||
2512 | { | ||
2513 | o->preloading = 0; | ||
2514 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
2515 | o->engine_data, | ||
2516 | obj); | ||
2517 | } | ||
2518 | obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output, | ||
2519 | o->engine_data); | ||
2520 | } | ||
2521 | o->engine_data = NULL; | ||
2522 | o->load_error = EVAS_LOAD_ERROR_NONE; | ||
2523 | o->cur.has_alpha = 1; | ||
2524 | o->cur.cspace = EVAS_COLORSPACE_ARGB8888; | ||
2525 | o->cur.image.w = 0; | ||
2526 | o->cur.image.h = 0; | ||
2527 | o->cur.image.stride = 0; | ||
2528 | } | ||
2529 | |||
2530 | static void | ||
2531 | evas_object_image_load(Evas_Object *obj) | ||
2532 | { | ||
2533 | Evas_Object_Image *o; | ||
2534 | Evas_Image_Load_Opts lo; | ||
2535 | |||
2536 | o = (Evas_Object_Image *)(obj->object_data); | ||
2537 | if (o->engine_data) return; | ||
2538 | |||
2539 | lo.scale_down_by = o->load_opts.scale_down_by; | ||
2540 | lo.dpi = o->load_opts.dpi; | ||
2541 | lo.w = o->load_opts.w; | ||
2542 | lo.h = o->load_opts.h; | ||
2543 | lo.region.x = o->load_opts.region.x; | ||
2544 | lo.region.y = o->load_opts.region.y; | ||
2545 | lo.region.w = o->load_opts.region.w; | ||
2546 | lo.region.h = o->load_opts.region.h; | ||
2547 | lo.orientation = o->load_opts.orientation; | ||
2548 | o->engine_data = obj->layer->evas->engine.func->image_load | ||
2549 | (obj->layer->evas->engine.data.output, | ||
2550 | o->cur.file, | ||
2551 | o->cur.key, | ||
2552 | &o->load_error, | ||
2553 | &lo); | ||
2554 | if (o->engine_data) | ||
2555 | { | ||
2556 | int w, h; | ||
2557 | int stride = 0; | ||
2558 | |||
2559 | obj->layer->evas->engine.func->image_size_get | ||
2560 | (obj->layer->evas->engine.data.output, | ||
2561 | o->engine_data, &w, &h); | ||
2562 | if (obj->layer->evas->engine.func->image_stride_get) | ||
2563 | obj->layer->evas->engine.func->image_stride_get | ||
2564 | (obj->layer->evas->engine.data.output, | ||
2565 | o->engine_data, &stride); | ||
2566 | else | ||
2567 | stride = w * 4; | ||
2568 | o->cur.has_alpha = obj->layer->evas->engine.func->image_alpha_get | ||
2569 | (obj->layer->evas->engine.data.output, | ||
2570 | o->engine_data); | ||
2571 | o->cur.cspace = obj->layer->evas->engine.func->image_colorspace_get | ||
2572 | (obj->layer->evas->engine.data.output, | ||
2573 | o->engine_data); | ||
2574 | o->cur.image.w = w; | ||
2575 | o->cur.image.h = h; | ||
2576 | o->cur.image.stride = stride; | ||
2577 | } | ||
2578 | else | ||
2579 | { | ||
2580 | o->load_error = EVAS_LOAD_ERROR_GENERIC; | ||
2581 | } | ||
2582 | } | ||
2583 | |||
2584 | static Evas_Coord | ||
2585 | evas_object_image_figure_x_fill(Evas_Object *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret) | ||
2586 | { | ||
2587 | Evas_Coord w; | ||
2588 | |||
2589 | w = ((size * obj->layer->evas->output.w) / | ||
2590 | (Evas_Coord)obj->layer->evas->viewport.w); | ||
2591 | if (size <= 0) size = 1; | ||
2592 | if (start > 0) | ||
2593 | { | ||
2594 | while (start - size > 0) start -= size; | ||
2595 | } | ||
2596 | else if (start < 0) | ||
2597 | { | ||
2598 | while (start < 0) start += size; | ||
2599 | } | ||
2600 | start = ((start * obj->layer->evas->output.w) / | ||
2601 | (Evas_Coord)obj->layer->evas->viewport.w); | ||
2602 | *size_ret = w; | ||
2603 | return start; | ||
2604 | } | ||
2605 | |||
2606 | static Evas_Coord | ||
2607 | evas_object_image_figure_y_fill(Evas_Object *obj, Evas_Coord start, Evas_Coord size, Evas_Coord *size_ret) | ||
2608 | { | ||
2609 | Evas_Coord h; | ||
2610 | |||
2611 | h = ((size * obj->layer->evas->output.h) / | ||
2612 | (Evas_Coord)obj->layer->evas->viewport.h); | ||
2613 | if (size <= 0) size = 1; | ||
2614 | if (start > 0) | ||
2615 | { | ||
2616 | while (start - size > 0) start -= size; | ||
2617 | } | ||
2618 | else if (start < 0) | ||
2619 | { | ||
2620 | while (start < 0) start += size; | ||
2621 | } | ||
2622 | start = ((start * obj->layer->evas->output.h) / | ||
2623 | (Evas_Coord)obj->layer->evas->viewport.h); | ||
2624 | *size_ret = h; | ||
2625 | return start; | ||
2626 | } | ||
2627 | |||
2628 | static void | ||
2629 | evas_object_image_init(Evas_Object *obj) | ||
2630 | { | ||
2631 | /* alloc image ob, setup methods and default values */ | ||
2632 | obj->object_data = evas_object_image_new(); | ||
2633 | /* set up default settings for this kind of object */ | ||
2634 | obj->cur.color.r = 255; | ||
2635 | obj->cur.color.g = 255; | ||
2636 | obj->cur.color.b = 255; | ||
2637 | obj->cur.color.a = 255; | ||
2638 | obj->cur.geometry.x = 0; | ||
2639 | obj->cur.geometry.y = 0; | ||
2640 | obj->cur.geometry.w = 0; | ||
2641 | obj->cur.geometry.h = 0; | ||
2642 | obj->cur.layer = 0; | ||
2643 | obj->cur.anti_alias = 0; | ||
2644 | obj->cur.render_op = EVAS_RENDER_BLEND; | ||
2645 | /* set up object-specific settings */ | ||
2646 | obj->prev = obj->cur; | ||
2647 | /* set up methods (compulsory) */ | ||
2648 | obj->func = &object_func; | ||
2649 | obj->type = o_type; | ||
2650 | } | ||
2651 | |||
2652 | static void * | ||
2653 | evas_object_image_new(void) | ||
2654 | { | ||
2655 | Evas_Object_Image *o; | ||
2656 | |||
2657 | /* alloc obj private data */ | ||
2658 | EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_image", Evas_Object_Image, 256, NULL); | ||
2659 | o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Image); | ||
2660 | if (!o) return NULL; | ||
2661 | EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Image); | ||
2662 | o->magic = MAGIC_OBJ_IMAGE; | ||
2663 | o->cur.fill.w = 0; | ||
2664 | o->cur.fill.h = 0; | ||
2665 | o->cur.smooth_scale = 1; | ||
2666 | o->cur.border.fill = 1; | ||
2667 | o->cur.border.scale = 1.0; | ||
2668 | o->cur.cspace = EVAS_COLORSPACE_ARGB8888; | ||
2669 | o->cur.spread = EVAS_TEXTURE_REPEAT; | ||
2670 | o->cur.opaque_valid = 0; | ||
2671 | o->cur.source = NULL; | ||
2672 | o->prev = o->cur; | ||
2673 | o->tmpf_fd = -1; | ||
2674 | return o; | ||
2675 | } | ||
2676 | |||
2677 | static void | ||
2678 | evas_object_image_free(Evas_Object *obj) | ||
2679 | { | ||
2680 | Evas_Object_Image *o; | ||
2681 | Eina_Rectangle *r; | ||
2682 | |||
2683 | /* frees private object data. very simple here */ | ||
2684 | o = (Evas_Object_Image *)(obj->object_data); | ||
2685 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
2686 | return; | ||
2687 | MAGIC_CHECK_END(); | ||
2688 | /* free obj */ | ||
2689 | _cleanup_tmpf(obj); | ||
2690 | if (o->cur.file) eina_stringshare_del(o->cur.file); | ||
2691 | if (o->cur.key) eina_stringshare_del(o->cur.key); | ||
2692 | if (o->cur.source) _proxy_unset(obj); | ||
2693 | if (o->engine_data) | ||
2694 | { | ||
2695 | if (o->preloading) | ||
2696 | { | ||
2697 | o->preloading = 0; | ||
2698 | obj->layer->evas->engine.func->image_data_preload_cancel(obj->layer->evas->engine.data.output, | ||
2699 | o->engine_data, | ||
2700 | obj); | ||
2701 | } | ||
2702 | obj->layer->evas->engine.func->image_free(obj->layer->evas->engine.data.output, | ||
2703 | o->engine_data); | ||
2704 | } | ||
2705 | if (o->video_surface) | ||
2706 | { | ||
2707 | o->video_surface = 0; | ||
2708 | obj->layer->evas->video_objects = eina_list_remove(obj->layer->evas->video_objects, obj); | ||
2709 | } | ||
2710 | o->engine_data = NULL; | ||
2711 | o->magic = 0; | ||
2712 | EINA_LIST_FREE(o->pixel_updates, r) | ||
2713 | eina_rectangle_free(r); | ||
2714 | EVAS_MEMPOOL_FREE(_mp_obj, o); | ||
2715 | } | ||
2716 | |||
2717 | static void | ||
2718 | evas_object_image_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y) | ||
2719 | { | ||
2720 | Evas_Object_Image *o; | ||
2721 | int imagew, imageh, uvw, uvh; | ||
2722 | void *pixels; | ||
2723 | |||
2724 | /* render object to surface with context, and offset by x,y */ | ||
2725 | o = (Evas_Object_Image *)(obj->object_data); | ||
2726 | |||
2727 | if ((o->cur.fill.w < 1) || (o->cur.fill.h < 1)) | ||
2728 | return; /* no error message, already printed in pre_render */ | ||
2729 | |||
2730 | /* Proxy sanity */ | ||
2731 | if (o->proxyrendering) | ||
2732 | { | ||
2733 | _proxy_error(obj, context, output, surface, x, y); | ||
2734 | return; | ||
2735 | } | ||
2736 | |||
2737 | /* We are displaying the overlay */ | ||
2738 | if (o->video_visible) | ||
2739 | { | ||
2740 | /* Create a transparent rectangle */ | ||
2741 | obj->layer->evas->engine.func->context_color_set(output, | ||
2742 | context, | ||
2743 | 0, 0, 0, 0); | ||
2744 | obj->layer->evas->engine.func->context_multiplier_unset(output, | ||
2745 | context); | ||
2746 | obj->layer->evas->engine.func->context_render_op_set(output, context, | ||
2747 | EVAS_RENDER_COPY); | ||
2748 | obj->layer->evas->engine.func->rectangle_draw(output, | ||
2749 | context, | ||
2750 | surface, | ||
2751 | obj->cur.geometry.x + x, | ||
2752 | obj->cur.geometry.y + y, | ||
2753 | obj->cur.geometry.w, | ||
2754 | obj->cur.geometry.h); | ||
2755 | |||
2756 | return ; | ||
2757 | } | ||
2758 | |||
2759 | obj->layer->evas->engine.func->context_color_set(output, | ||
2760 | context, | ||
2761 | 255, 255, 255, 255); | ||
2762 | |||
2763 | if ((obj->cur.cache.clip.r == 255) && | ||
2764 | (obj->cur.cache.clip.g == 255) && | ||
2765 | (obj->cur.cache.clip.b == 255) && | ||
2766 | (obj->cur.cache.clip.a == 255)) | ||
2767 | { | ||
2768 | obj->layer->evas->engine.func->context_multiplier_unset(output, | ||
2769 | context); | ||
2770 | } | ||
2771 | else | ||
2772 | obj->layer->evas->engine.func->context_multiplier_set(output, | ||
2773 | context, | ||
2774 | obj->cur.cache.clip.r, | ||
2775 | obj->cur.cache.clip.g, | ||
2776 | obj->cur.cache.clip.b, | ||
2777 | obj->cur.cache.clip.a); | ||
2778 | |||
2779 | obj->layer->evas->engine.func->context_render_op_set(output, context, | ||
2780 | obj->cur.render_op); | ||
2781 | |||
2782 | if (!o->cur.source) | ||
2783 | { | ||
2784 | pixels = o->engine_data; | ||
2785 | imagew = o->cur.image.w; | ||
2786 | imageh = o->cur.image.h; | ||
2787 | uvw = imagew; | ||
2788 | uvh = imageh; | ||
2789 | } | ||
2790 | else if (o->cur.source->proxy.surface && !o->cur.source->proxy.redraw) | ||
2791 | { | ||
2792 | pixels = o->cur.source->proxy.surface; | ||
2793 | imagew = o->cur.source->proxy.w; | ||
2794 | imageh = o->cur.source->proxy.h; | ||
2795 | uvw = imagew; | ||
2796 | uvh = imageh; | ||
2797 | } | ||
2798 | else if (o->cur.source->type == o_type && | ||
2799 | ((Evas_Object_Image *)o->cur.source->object_data)->engine_data) | ||
2800 | { | ||
2801 | Evas_Object_Image *oi; | ||
2802 | oi = o->cur.source->object_data; | ||
2803 | pixels = oi->engine_data; | ||
2804 | imagew = oi->cur.image.w; | ||
2805 | imageh = oi->cur.image.h; | ||
2806 | uvw = o->cur.source->cur.geometry.w; | ||
2807 | uvh = o->cur.source->cur.geometry.h; | ||
2808 | } | ||
2809 | else | ||
2810 | { | ||
2811 | o->proxyrendering = 1; | ||
2812 | _proxy_subrender(obj->layer->evas, o->cur.source); | ||
2813 | pixels = o->cur.source->proxy.surface; | ||
2814 | imagew = o->cur.source->proxy.w; | ||
2815 | imageh = o->cur.source->proxy.h; | ||
2816 | uvw = imagew; | ||
2817 | uvh = imageh; | ||
2818 | o->proxyrendering = 0; | ||
2819 | } | ||
2820 | |||
2821 | #if 0 // filtering disabled | ||
2822 | /* Now check/update filter */ | ||
2823 | if (obj->filter && obj->filter->filter) | ||
2824 | { | ||
2825 | Filtered_Image *fi = NULL; | ||
2826 | //printf("%p has filter: %s\n", obj,obj->filter->dirty?"dirty":"clean"); | ||
2827 | if (obj->filter->dirty) | ||
2828 | { | ||
2829 | if (obj->filter->mode != EVAS_FILTER_MODE_BELOW) | ||
2830 | { | ||
2831 | uint32_t len; | ||
2832 | uint8_t *key; | ||
2833 | |||
2834 | if (obj->filter->key) free(obj->filter->key); | ||
2835 | obj->filter->key = NULL; | ||
2836 | obj->filter->len = 0; | ||
2837 | key = evas_filter_key_get(obj->filter, &len); | ||
2838 | if (key) | ||
2839 | { | ||
2840 | obj->filter->key = key; | ||
2841 | obj->filter->len = len; | ||
2842 | fi = obj->layer->evas->engine.func->image_filtered_get | ||
2843 | (o->engine_data, key, len); | ||
2844 | if (obj->filter->cached && fi != obj->filter->cached) | ||
2845 | { | ||
2846 | obj->layer->evas->engine.func->image_filtered_free | ||
2847 | (o->engine_data, obj->filter->cached); | ||
2848 | obj->filter->cached = NULL; | ||
2849 | } | ||
2850 | } | ||
2851 | } | ||
2852 | else if (obj->filter->cached) | ||
2853 | { | ||
2854 | obj->layer->evas->engine.func->image_filtered_free | ||
2855 | (o->engine_data, obj->filter->cached); | ||
2856 | } | ||
2857 | if (!fi) | ||
2858 | fi = image_filter_update(obj->layer->evas, obj, pixels, | ||
2859 | imagew, imageh, &imagew, &imageh); | ||
2860 | pixels = fi->image; | ||
2861 | obj->filter->dirty = 0; | ||
2862 | obj->filter->cached = fi; | ||
2863 | } | ||
2864 | else | ||
2865 | { | ||
2866 | fi = obj->filter->cached; | ||
2867 | pixels = fi->image; | ||
2868 | } | ||
2869 | } | ||
2870 | #endif | ||
2871 | |||
2872 | if (pixels) | ||
2873 | { | ||
2874 | Evas_Coord idw, idh, idx, idy; | ||
2875 | int ix, iy, iw, ih; | ||
2876 | |||
2877 | if (o->dirty_pixels) | ||
2878 | { | ||
2879 | if (o->func.get_pixels) | ||
2880 | { | ||
2881 | o->func.get_pixels(o->func.get_pixels_data, obj); | ||
2882 | if (o->engine_data != pixels) | ||
2883 | pixels = o->engine_data; | ||
2884 | o->engine_data = obj->layer->evas->engine.func->image_dirty_region | ||
2885 | (obj->layer->evas->engine.data.output, o->engine_data, | ||
2886 | 0, 0, o->cur.image.w, o->cur.image.h); | ||
2887 | } | ||
2888 | o->dirty_pixels = 0; | ||
2889 | } | ||
2890 | if ((obj->cur.map) && (obj->cur.map->count > 3) && (obj->cur.usemap)) | ||
2891 | { | ||
2892 | const Evas_Map_Point *p, *p_end; | ||
2893 | RGBA_Map_Point pts[obj->cur.map->count], *pt; | ||
2894 | |||
2895 | p = obj->cur.map->points; | ||
2896 | p_end = p + obj->cur.map->count; | ||
2897 | pt = pts; | ||
2898 | |||
2899 | pts[0].px = obj->cur.map->persp.px << FP; | ||
2900 | pts[0].py = obj->cur.map->persp.py << FP; | ||
2901 | pts[0].foc = obj->cur.map->persp.foc << FP; | ||
2902 | pts[0].z0 = obj->cur.map->persp.z0 << FP; | ||
2903 | // draw geom +x +y | ||
2904 | for (; p < p_end; p++, pt++) | ||
2905 | { | ||
2906 | pt->x = (lround(p->x) + x) * FP1; | ||
2907 | pt->y = (lround(p->y) + y) * FP1; | ||
2908 | pt->z = (lround(p->z) ) * FP1; | ||
2909 | pt->fx = p->px; | ||
2910 | pt->fy = p->py; | ||
2911 | pt->fz = p->z; | ||
2912 | pt->u = ((lround(p->u) * imagew) / uvw) * FP1; | ||
2913 | pt->v = ((lround(p->v) * imageh) / uvh) * FP1; | ||
2914 | if (pt->u < 0) pt->u = 0; | ||
2915 | else if (pt->u > (imagew * FP1)) pt->u = (imagew * FP1); | ||
2916 | if (pt->v < 0) pt->v = 0; | ||
2917 | else if (pt->v > (imageh * FP1)) pt->v = (imageh * FP1); | ||
2918 | pt->col = ARGB_JOIN(p->a, p->r, p->g, p->b); | ||
2919 | } | ||
2920 | if (obj->cur.map->count & 0x1) | ||
2921 | { | ||
2922 | pts[obj->cur.map->count] = pts[obj->cur.map->count -1]; | ||
2923 | } | ||
2924 | |||
2925 | obj->layer->evas->engine.func->image_map_draw | ||
2926 | (output, context, surface, pixels, obj->cur.map->count, | ||
2927 | pts, o->cur.smooth_scale | obj->cur.map->smooth, 0); | ||
2928 | } | ||
2929 | else | ||
2930 | { | ||
2931 | obj->layer->evas->engine.func->image_scale_hint_set(output, | ||
2932 | pixels, | ||
2933 | o->scale_hint); | ||
2934 | /* This is technically a bug here: If the value is recreated | ||
2935 | * (which is returned)it may be a new object, however exactly 0 | ||
2936 | * of all the evas engines do this. */ | ||
2937 | obj->layer->evas->engine.func->image_border_set(output, pixels, | ||
2938 | o->cur.border.l, o->cur.border.r, | ||
2939 | o->cur.border.t, o->cur.border.b); | ||
2940 | idx = evas_object_image_figure_x_fill(obj, o->cur.fill.x, o->cur.fill.w, &idw); | ||
2941 | idy = evas_object_image_figure_y_fill(obj, o->cur.fill.y, o->cur.fill.h, &idh); | ||
2942 | if (idw < 1) idw = 1; | ||
2943 | if (idh < 1) idh = 1; | ||
2944 | if (idx > 0) idx -= idw; | ||
2945 | if (idy > 0) idy -= idh; | ||
2946 | while ((int)idx < obj->cur.geometry.w) | ||
2947 | { | ||
2948 | Evas_Coord ydy; | ||
2949 | int dobreak_w = 0; | ||
2950 | |||
2951 | ydy = idy; | ||
2952 | ix = idx; | ||
2953 | if ((o->cur.fill.w == obj->cur.geometry.w) && | ||
2954 | (o->cur.fill.x == 0)) | ||
2955 | { | ||
2956 | dobreak_w = 1; | ||
2957 | iw = obj->cur.geometry.w; | ||
2958 | } | ||
2959 | else | ||
2960 | iw = ((int)(idx + idw)) - ix; | ||
2961 | while ((int)idy < obj->cur.geometry.h) | ||
2962 | { | ||
2963 | int dobreak_h = 0; | ||
2964 | |||
2965 | iy = idy; | ||
2966 | if ((o->cur.fill.h == obj->cur.geometry.h) && | ||
2967 | (o->cur.fill.y == 0)) | ||
2968 | { | ||
2969 | ih = obj->cur.geometry.h; | ||
2970 | dobreak_h = 1; | ||
2971 | } | ||
2972 | else | ||
2973 | ih = ((int)(idy + idh)) - iy; | ||
2974 | if ((o->cur.border.l == 0) && | ||
2975 | (o->cur.border.r == 0) && | ||
2976 | (o->cur.border.t == 0) && | ||
2977 | (o->cur.border.b == 0) && | ||
2978 | (o->cur.border.fill != 0)) | ||
2979 | obj->layer->evas->engine.func->image_draw(output, | ||
2980 | context, | ||
2981 | surface, | ||
2982 | pixels, | ||
2983 | 0, 0, | ||
2984 | imagew, | ||
2985 | imageh, | ||
2986 | obj->cur.geometry.x + ix + x, | ||
2987 | obj->cur.geometry.y + iy + y, | ||
2988 | iw, ih, | ||
2989 | o->cur.smooth_scale); | ||
2990 | else | ||
2991 | { | ||
2992 | int inx, iny, inw, inh, outx, outy, outw, outh; | ||
2993 | int bl, br, bt, bb, bsl, bsr, bst, bsb; | ||
2994 | int imw, imh, ox, oy; | ||
2995 | |||
2996 | ox = obj->cur.geometry.x + ix + x; | ||
2997 | oy = obj->cur.geometry.y + iy + y; | ||
2998 | imw = imagew; | ||
2999 | imh = imageh; | ||
3000 | bl = o->cur.border.l; | ||
3001 | br = o->cur.border.r; | ||
3002 | bt = o->cur.border.t; | ||
3003 | bb = o->cur.border.b; | ||
3004 | if ((bl + br) > iw) | ||
3005 | { | ||
3006 | bl = iw / 2; | ||
3007 | br = iw - bl; | ||
3008 | } | ||
3009 | if ((bl + br) > imw) | ||
3010 | { | ||
3011 | bl = imw / 2; | ||
3012 | br = imw - bl; | ||
3013 | } | ||
3014 | if ((bt + bb) > ih) | ||
3015 | { | ||
3016 | bt = ih / 2; | ||
3017 | bb = ih - bt; | ||
3018 | } | ||
3019 | if ((bt + bb) > imh) | ||
3020 | { | ||
3021 | bt = imh / 2; | ||
3022 | bb = imh - bt; | ||
3023 | } | ||
3024 | if (o->cur.border.scale != 1.0) | ||
3025 | { | ||
3026 | bsl = ((double)bl * o->cur.border.scale); | ||
3027 | bsr = ((double)br * o->cur.border.scale); | ||
3028 | bst = ((double)bt * o->cur.border.scale); | ||
3029 | bsb = ((double)bb * o->cur.border.scale); | ||
3030 | } | ||
3031 | else | ||
3032 | { | ||
3033 | bsl = bl; bsr = br; bst = bt; bsb = bb; | ||
3034 | } | ||
3035 | // #-- | ||
3036 | // | | ||
3037 | inx = 0; iny = 0; | ||
3038 | inw = bl; inh = bt; | ||
3039 | outx = ox; outy = oy; | ||
3040 | outw = bsl; outh = bst; | ||
3041 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3042 | // .## | ||
3043 | // | | ||
3044 | inx = bl; iny = 0; | ||
3045 | inw = imw - bl - br; inh = bt; | ||
3046 | outx = ox + bsl; outy = oy; | ||
3047 | outw = iw - bsl - bsr; outh = bst; | ||
3048 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3049 | // --# | ||
3050 | // | | ||
3051 | inx = imw - br; iny = 0; | ||
3052 | inw = br; inh = bt; | ||
3053 | outx = ox + iw - bsr; outy = oy; | ||
3054 | outw = bsr; outh = bst; | ||
3055 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3056 | // .-- | ||
3057 | // # | ||
3058 | inx = 0; iny = bt; | ||
3059 | inw = bl; inh = imh - bt - bb; | ||
3060 | outx = ox; outy = oy + bst; | ||
3061 | outw = bsl; outh = ih - bst - bsb; | ||
3062 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3063 | // .--. | ||
3064 | // |##| | ||
3065 | if (o->cur.border.fill > EVAS_BORDER_FILL_NONE) | ||
3066 | { | ||
3067 | inx = bl; iny = bt; | ||
3068 | inw = imw - bl - br; inh = imh - bt - bb; | ||
3069 | outx = ox + bsl; outy = oy + bst; | ||
3070 | outw = iw - bsl - bsr; outh = ih - bst - bsb; | ||
3071 | if ((o->cur.border.fill == EVAS_BORDER_FILL_SOLID) && | ||
3072 | (obj->cur.cache.clip.a == 255) && | ||
3073 | (obj->cur.render_op == EVAS_RENDER_BLEND)) | ||
3074 | { | ||
3075 | obj->layer->evas->engine.func->context_render_op_set(output, context, | ||
3076 | EVAS_RENDER_COPY); | ||
3077 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3078 | obj->layer->evas->engine.func->context_render_op_set(output, context, | ||
3079 | obj->cur.render_op); | ||
3080 | } | ||
3081 | else | ||
3082 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3083 | } | ||
3084 | // --. | ||
3085 | // # | ||
3086 | inx = imw - br; iny = bt; | ||
3087 | inw = br; inh = imh - bt - bb; | ||
3088 | outx = ox + iw - bsr; outy = oy + bst; | ||
3089 | outw = bsr; outh = ih - bst - bsb; | ||
3090 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3091 | // | | ||
3092 | // #-- | ||
3093 | inx = 0; iny = imh - bb; | ||
3094 | inw = bl; inh = bb; | ||
3095 | outx = ox; outy = oy + ih - bsb; | ||
3096 | outw = bsl; outh = bsb; | ||
3097 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3098 | // | | ||
3099 | // .## | ||
3100 | inx = bl; iny = imh - bb; | ||
3101 | inw = imw - bl - br; inh = bb; | ||
3102 | outx = ox + bsl; outy = oy + ih - bsb; | ||
3103 | outw = iw - bsl - bsr; outh = bsb; | ||
3104 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3105 | // | | ||
3106 | // --# | ||
3107 | inx = imw - br; iny = imh - bb; | ||
3108 | inw = br; inh = bb; | ||
3109 | outx = ox + iw - bsr; outy = oy + ih - bsb; | ||
3110 | outw = bsr; outh = bsb; | ||
3111 | obj->layer->evas->engine.func->image_draw(output, context, surface, pixels, inx, iny, inw, inh, outx, outy, outw, outh, o->cur.smooth_scale); | ||
3112 | } | ||
3113 | idy += idh; | ||
3114 | if (dobreak_h) break; | ||
3115 | } | ||
3116 | idx += idw; | ||
3117 | idy = ydy; | ||
3118 | if (dobreak_w) break; | ||
3119 | } | ||
3120 | } | ||
3121 | } | ||
3122 | } | ||
3123 | |||
3124 | static void | ||
3125 | evas_object_image_render_pre(Evas_Object *obj) | ||
3126 | { | ||
3127 | Evas_Object_Image *o; | ||
3128 | int is_v = 0, was_v = 0; | ||
3129 | Evas *e; | ||
3130 | |||
3131 | /* dont pre-render the obj twice! */ | ||
3132 | if (obj->pre_render_done) return; | ||
3133 | obj->pre_render_done = 1; | ||
3134 | /* pre-render phase. this does anything an object needs to do just before */ | ||
3135 | /* rendering. this could mean loading the image data, retrieving it from */ | ||
3136 | /* elsewhere, decoding video etc. */ | ||
3137 | /* then when this is done the object needs to figure if it changed and */ | ||
3138 | /* if so what and where and add the appropriate redraw rectangles */ | ||
3139 | o = (Evas_Object_Image *)(obj->object_data); | ||
3140 | e = obj->layer->evas; | ||
3141 | |||
3142 | if ((o->cur.fill.w < 1) || (o->cur.fill.h < 1)) | ||
3143 | { | ||
3144 | ERR("%p has invalid fill size: %dx%d. Ignored", | ||
3145 | obj, o->cur.fill.w, o->cur.fill.h); | ||
3146 | return; | ||
3147 | } | ||
3148 | |||
3149 | /* if someone is clipping this obj - go calculate the clipper */ | ||
3150 | if (obj->cur.clipper) | ||
3151 | { | ||
3152 | if (obj->cur.cache.clip.dirty) | ||
3153 | evas_object_clip_recalc(obj->cur.clipper); | ||
3154 | obj->cur.clipper->func->render_pre(obj->cur.clipper); | ||
3155 | } | ||
3156 | /* Proxy: Do it early */ | ||
3157 | if (o->cur.source && | ||
3158 | (o->cur.source->proxy.redraw || o->cur.source->changed)) | ||
3159 | { | ||
3160 | /* XXX: Do I need to sort out the map here? */ | ||
3161 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3162 | goto done; | ||
3163 | } | ||
3164 | |||
3165 | /* now figure what changed and add draw rects */ | ||
3166 | /* if it just became visible or invisible */ | ||
3167 | is_v = evas_object_is_visible(obj); | ||
3168 | was_v = evas_object_was_visible(obj); | ||
3169 | if (is_v != was_v) | ||
3170 | { | ||
3171 | evas_object_render_pre_visible_change(&e->clip_changes, obj, is_v, was_v); | ||
3172 | if (!o->pixel_updates) goto done; | ||
3173 | } | ||
3174 | if ((obj->cur.map != obj->prev.map) || | ||
3175 | (obj->cur.usemap != obj->prev.usemap)) | ||
3176 | { | ||
3177 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3178 | goto done; | ||
3179 | } | ||
3180 | /* it's not visible - we accounted for it appearing or not so just abort */ | ||
3181 | if (!is_v) goto done; | ||
3182 | /* clipper changed this is in addition to anything else for obj */ | ||
3183 | evas_object_render_pre_clipper_change(&e->clip_changes, obj); | ||
3184 | /* if we restacked (layer or just within a layer) and don't clip anyone */ | ||
3185 | if (obj->restack) | ||
3186 | { | ||
3187 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3188 | if (!o->pixel_updates) goto done; | ||
3189 | } | ||
3190 | /* if it changed color */ | ||
3191 | if ((obj->cur.color.r != obj->prev.color.r) || | ||
3192 | (obj->cur.color.g != obj->prev.color.g) || | ||
3193 | (obj->cur.color.b != obj->prev.color.b) || | ||
3194 | (obj->cur.color.a != obj->prev.color.a)) | ||
3195 | { | ||
3196 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3197 | if (!o->pixel_updates) goto done; | ||
3198 | } | ||
3199 | /* if it changed render op */ | ||
3200 | if (obj->cur.render_op != obj->prev.render_op) | ||
3201 | { | ||
3202 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3203 | if (!o->pixel_updates) goto done; | ||
3204 | } | ||
3205 | /* if it changed anti_alias */ | ||
3206 | if (obj->cur.anti_alias != obj->prev.anti_alias) | ||
3207 | { | ||
3208 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3209 | if (!o->pixel_updates) goto done; | ||
3210 | } | ||
3211 | if (o->changed) | ||
3212 | { | ||
3213 | if (((o->cur.file) && (!o->prev.file)) || | ||
3214 | ((!o->cur.file) && (o->prev.file)) || | ||
3215 | ((o->cur.key) && (!o->prev.key)) || | ||
3216 | ((!o->cur.key) && (o->prev.key)) | ||
3217 | ) | ||
3218 | { | ||
3219 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3220 | if (!o->pixel_updates) goto done; | ||
3221 | } | ||
3222 | if ((o->cur.image.w != o->prev.image.w) || | ||
3223 | (o->cur.image.h != o->prev.image.h) || | ||
3224 | (o->cur.has_alpha != o->prev.has_alpha) || | ||
3225 | (o->cur.cspace != o->prev.cspace) || | ||
3226 | (o->cur.smooth_scale != o->prev.smooth_scale)) | ||
3227 | { | ||
3228 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3229 | if (!o->pixel_updates) goto done; | ||
3230 | } | ||
3231 | if ((o->cur.border.l != o->prev.border.l) || | ||
3232 | (o->cur.border.r != o->prev.border.r) || | ||
3233 | (o->cur.border.t != o->prev.border.t) || | ||
3234 | (o->cur.border.b != o->prev.border.b) || | ||
3235 | (o->cur.border.fill != o->prev.border.fill) || | ||
3236 | (o->cur.border.scale != o->prev.border.scale)) | ||
3237 | { | ||
3238 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3239 | if (!o->pixel_updates) goto done; | ||
3240 | } | ||
3241 | if (o->dirty_pixels) | ||
3242 | { | ||
3243 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3244 | if (!o->pixel_updates) goto done; | ||
3245 | } | ||
3246 | if (o->cur.frame != o->prev.frame) | ||
3247 | { | ||
3248 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3249 | if (!o->pixel_updates) goto done; | ||
3250 | } | ||
3251 | |||
3252 | } | ||
3253 | /* if it changed geometry - and obviously not visibility or color */ | ||
3254 | /* calculate differences since we have a constant color fill */ | ||
3255 | /* we really only need to update the differences */ | ||
3256 | #if 0 // XXX: maybe buggy? | ||
3257 | if (((obj->cur.geometry.x != obj->prev.geometry.x) || | ||
3258 | (obj->cur.geometry.y != obj->prev.geometry.y) || | ||
3259 | (obj->cur.geometry.w != obj->prev.geometry.w) || | ||
3260 | (obj->cur.geometry.h != obj->prev.geometry.h)) && | ||
3261 | (o->cur.fill.w == o->prev.fill.w) && | ||
3262 | (o->cur.fill.h == o->prev.fill.h) && | ||
3263 | ((o->cur.fill.x + obj->cur.geometry.x) == (o->prev.fill.x + obj->prev.geometry.x)) && | ||
3264 | ((o->cur.fill.y + obj->cur.geometry.y) == (o->prev.fill.y + obj->prev.geometry.y)) && | ||
3265 | (!o->pixel_updates) | ||
3266 | ) | ||
3267 | { | ||
3268 | evas_rects_return_difference_rects(&e->clip_changes, | ||
3269 | obj->cur.geometry.x, | ||
3270 | obj->cur.geometry.y, | ||
3271 | obj->cur.geometry.w, | ||
3272 | obj->cur.geometry.h, | ||
3273 | obj->prev.geometry.x, | ||
3274 | obj->prev.geometry.y, | ||
3275 | obj->prev.geometry.w, | ||
3276 | obj->prev.geometry.h); | ||
3277 | if (!o->pixel_updates) goto done; | ||
3278 | } | ||
3279 | #endif | ||
3280 | if (((obj->cur.geometry.x != obj->prev.geometry.x) || | ||
3281 | (obj->cur.geometry.y != obj->prev.geometry.y) || | ||
3282 | (obj->cur.geometry.w != obj->prev.geometry.w) || | ||
3283 | (obj->cur.geometry.h != obj->prev.geometry.h)) | ||
3284 | ) | ||
3285 | { | ||
3286 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3287 | if (!o->pixel_updates) goto done; | ||
3288 | } | ||
3289 | if (o->changed) | ||
3290 | { | ||
3291 | if ((o->cur.fill.x != o->prev.fill.x) || | ||
3292 | (o->cur.fill.y != o->prev.fill.y) || | ||
3293 | (o->cur.fill.w != o->prev.fill.w) || | ||
3294 | (o->cur.fill.h != o->prev.fill.h)) | ||
3295 | { | ||
3296 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3297 | if (!o->pixel_updates) goto done; | ||
3298 | } | ||
3299 | if (o->pixel_updates) | ||
3300 | { | ||
3301 | if ((o->cur.border.l == 0) && | ||
3302 | (o->cur.border.r == 0) && | ||
3303 | (o->cur.border.t == 0) && | ||
3304 | (o->cur.border.b == 0) && | ||
3305 | (o->cur.image.w > 0) && | ||
3306 | (o->cur.image.h > 0) && | ||
3307 | (!((obj->cur.map) && (obj->cur.usemap)))) | ||
3308 | { | ||
3309 | Eina_Rectangle *rr; | ||
3310 | |||
3311 | EINA_LIST_FREE(o->pixel_updates, rr) | ||
3312 | { | ||
3313 | Evas_Coord idw, idh, idx, idy; | ||
3314 | int x, y, w, h; | ||
3315 | |||
3316 | e->engine.func->image_dirty_region(e->engine.data.output, o->engine_data, rr->x, rr->y, rr->w, rr->h); | ||
3317 | |||
3318 | idx = evas_object_image_figure_x_fill(obj, o->cur.fill.x, o->cur.fill.w, &idw); | ||
3319 | idy = evas_object_image_figure_y_fill(obj, o->cur.fill.y, o->cur.fill.h, &idh); | ||
3320 | |||
3321 | if (idw < 1) idw = 1; | ||
3322 | if (idh < 1) idh = 1; | ||
3323 | if (idx > 0) idx -= idw; | ||
3324 | if (idy > 0) idy -= idh; | ||
3325 | while (idx < obj->cur.geometry.w) | ||
3326 | { | ||
3327 | Evas_Coord ydy; | ||
3328 | |||
3329 | ydy = idy; | ||
3330 | x = idx; | ||
3331 | w = ((int)(idx + idw)) - x; | ||
3332 | while (idy < obj->cur.geometry.h) | ||
3333 | { | ||
3334 | Eina_Rectangle r; | ||
3335 | |||
3336 | y = idy; | ||
3337 | h = ((int)(idy + idh)) - y; | ||
3338 | |||
3339 | r.x = ((rr->x - 1) * w) / o->cur.image.w; | ||
3340 | r.y = ((rr->y - 1) * h) / o->cur.image.h; | ||
3341 | r.w = ((rr->w + 2) * w) / o->cur.image.w; | ||
3342 | r.h = ((rr->h + 2) * h) / o->cur.image.h; | ||
3343 | r.x += obj->cur.geometry.x + x; | ||
3344 | r.y += obj->cur.geometry.y + y; | ||
3345 | RECTS_CLIP_TO_RECT(r.x, r.y, r.w, r.h, | ||
3346 | obj->cur.cache.clip.x, obj->cur.cache.clip.y, | ||
3347 | obj->cur.cache.clip.w, obj->cur.cache.clip.h); | ||
3348 | evas_add_rect(&e->clip_changes, r.x, r.y, r.w, r.h); | ||
3349 | idy += h; | ||
3350 | } | ||
3351 | idx += idw; | ||
3352 | idy = ydy; | ||
3353 | } | ||
3354 | eina_rectangle_free(rr); | ||
3355 | } | ||
3356 | goto done; | ||
3357 | } | ||
3358 | else | ||
3359 | { | ||
3360 | Eina_Rectangle *r; | ||
3361 | |||
3362 | EINA_LIST_FREE(o->pixel_updates, r) | ||
3363 | eina_rectangle_free(r); | ||
3364 | e->engine.func->image_dirty_region(e->engine.data.output, o->engine_data, 0, 0, o->cur.image.w, o->cur.image.h); | ||
3365 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3366 | goto done; | ||
3367 | } | ||
3368 | } | ||
3369 | } | ||
3370 | #if 0 // filtering disabled | ||
3371 | if (obj->filter && obj->filter->dirty) | ||
3372 | { | ||
3373 | evas_object_render_pre_prev_cur_add(&e->clip_changes, obj); | ||
3374 | } | ||
3375 | #endif | ||
3376 | /* it obviously didn't change - add a NO obscure - this "unupdates" this */ | ||
3377 | /* area so if there were updates for it they get wiped. don't do it if we */ | ||
3378 | /* aren't fully opaque and we are visible */ | ||
3379 | if (evas_object_is_visible(obj) && | ||
3380 | evas_object_is_opaque(obj)) | ||
3381 | { | ||
3382 | Evas_Coord x, y, w, h; | ||
3383 | |||
3384 | x = obj->cur.cache.clip.x; | ||
3385 | y = obj->cur.cache.clip.y; | ||
3386 | w = obj->cur.cache.clip.w; | ||
3387 | h = obj->cur.cache.clip.h; | ||
3388 | if (obj->cur.clipper) | ||
3389 | { | ||
3390 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
3391 | obj->cur.clipper->cur.cache.clip.x, | ||
3392 | obj->cur.clipper->cur.cache.clip.y, | ||
3393 | obj->cur.clipper->cur.cache.clip.w, | ||
3394 | obj->cur.clipper->cur.cache.clip.h); | ||
3395 | } | ||
3396 | e->engine.func->output_redraws_rect_del(e->engine.data.output, | ||
3397 | x, y, w, h); | ||
3398 | } | ||
3399 | done: | ||
3400 | evas_object_render_pre_effect_updates(&e->clip_changes, obj, is_v, was_v); | ||
3401 | } | ||
3402 | |||
3403 | static void | ||
3404 | evas_object_image_render_post(Evas_Object *obj) | ||
3405 | { | ||
3406 | Evas_Object_Image *o; | ||
3407 | Eina_Rectangle *r; | ||
3408 | |||
3409 | /* this moves the current data to the previous state parts of the object */ | ||
3410 | /* in whatever way is safest for the object. also if we don't need object */ | ||
3411 | /* data anymore we can free it if the object deems this is a good idea */ | ||
3412 | o = (Evas_Object_Image *)(obj->object_data); | ||
3413 | /* remove those pesky changes */ | ||
3414 | evas_object_clip_changes_clean(obj); | ||
3415 | EINA_LIST_FREE(o->pixel_updates, r) | ||
3416 | eina_rectangle_free(r); | ||
3417 | /* move cur to prev safely for object data */ | ||
3418 | obj->prev = obj->cur; | ||
3419 | o->prev = o->cur; | ||
3420 | o->changed = 0; | ||
3421 | /* FIXME: copy strings across */ | ||
3422 | } | ||
3423 | |||
3424 | static unsigned int evas_object_image_id_get(Evas_Object *obj) | ||
3425 | { | ||
3426 | Evas_Object_Image *o; | ||
3427 | |||
3428 | o = (Evas_Object_Image *)(obj->object_data); | ||
3429 | if (!o) return 0; | ||
3430 | return MAGIC_OBJ_IMAGE; | ||
3431 | } | ||
3432 | |||
3433 | static unsigned int evas_object_image_visual_id_get(Evas_Object *obj) | ||
3434 | { | ||
3435 | Evas_Object_Image *o; | ||
3436 | |||
3437 | o = (Evas_Object_Image *)(obj->object_data); | ||
3438 | if (!o) return 0; | ||
3439 | return MAGIC_OBJ_IMAGE; | ||
3440 | } | ||
3441 | |||
3442 | static void *evas_object_image_engine_data_get(Evas_Object *obj) | ||
3443 | { | ||
3444 | Evas_Object_Image *o; | ||
3445 | |||
3446 | o = (Evas_Object_Image *)(obj->object_data); | ||
3447 | if (!o) return NULL; | ||
3448 | return o->engine_data; | ||
3449 | } | ||
3450 | |||
3451 | static int | ||
3452 | evas_object_image_is_opaque(Evas_Object *obj) | ||
3453 | { | ||
3454 | Evas_Object_Image *o; | ||
3455 | |||
3456 | /* this returns 1 if the internal object data implies that the object is */ | ||
3457 | /* currently fully opaque over the entire rectangle it occupies */ | ||
3458 | o = (Evas_Object_Image *)(obj->object_data); | ||
3459 | /* disable caching due tyo maps screwing with this | ||
3460 | o->cur.opaque_valid = 0; | ||
3461 | if (o->cur.opaque_valid) | ||
3462 | { | ||
3463 | if (!o->cur.opaque) return 0; | ||
3464 | } | ||
3465 | else | ||
3466 | */ | ||
3467 | { | ||
3468 | o->cur.opaque = 0; | ||
3469 | /* disable caching */ | ||
3470 | /* o->cur.opaque_valid = 1; */ | ||
3471 | if ((o->cur.fill.w < 1) || (o->cur.fill.h < 1)) | ||
3472 | return o->cur.opaque; | ||
3473 | if (((o->cur.border.l != 0) || | ||
3474 | (o->cur.border.r != 0) || | ||
3475 | (o->cur.border.t != 0) || | ||
3476 | (o->cur.border.b != 0)) && | ||
3477 | (!o->cur.border.fill)) return o->cur.opaque; | ||
3478 | if (!o->engine_data) return o->cur.opaque; | ||
3479 | o->cur.opaque = 1; | ||
3480 | } | ||
3481 | // FIXME: use proxy | ||
3482 | if (o->cur.source) | ||
3483 | { | ||
3484 | o->cur.opaque = evas_object_is_opaque(o->cur.source); | ||
3485 | return o->cur.opaque; /* FIXME: Should go poke at the object */ | ||
3486 | } | ||
3487 | if (o->cur.has_alpha) | ||
3488 | { | ||
3489 | o->cur.opaque = 0; | ||
3490 | return o->cur.opaque; | ||
3491 | } | ||
3492 | if ((obj->cur.map) && (obj->cur.usemap)) | ||
3493 | { | ||
3494 | Evas_Map *m = obj->cur.map; | ||
3495 | |||
3496 | if ((m->points[0].a == 255) && | ||
3497 | (m->points[1].a == 255) && | ||
3498 | (m->points[2].a == 255) && | ||
3499 | (m->points[3].a == 255)) | ||
3500 | { | ||
3501 | if ( | ||
3502 | ((m->points[0].x == m->points[3].x) && | ||
3503 | (m->points[1].x == m->points[2].x) && | ||
3504 | (m->points[0].y == m->points[1].y) && | ||
3505 | (m->points[2].y == m->points[3].y)) | ||
3506 | || | ||
3507 | ((m->points[0].x == m->points[1].x) && | ||
3508 | (m->points[2].x == m->points[3].x) && | ||
3509 | (m->points[0].y == m->points[3].y) && | ||
3510 | (m->points[1].y == m->points[2].y)) | ||
3511 | ) | ||
3512 | { | ||
3513 | if ((m->points[0].x == obj->cur.geometry.x) && | ||
3514 | (m->points[0].y == obj->cur.geometry.y) && | ||
3515 | (m->points[2].x == (obj->cur.geometry.x + obj->cur.geometry.w)) && | ||
3516 | (m->points[2].y == (obj->cur.geometry.y + obj->cur.geometry.h))) | ||
3517 | return o->cur.opaque; | ||
3518 | } | ||
3519 | } | ||
3520 | o->cur.opaque = 0; | ||
3521 | return o->cur.opaque; | ||
3522 | } | ||
3523 | if (obj->cur.render_op == EVAS_RENDER_COPY) return o->cur.opaque; | ||
3524 | return o->cur.opaque; | ||
3525 | } | ||
3526 | |||
3527 | static int | ||
3528 | evas_object_image_was_opaque(Evas_Object *obj) | ||
3529 | { | ||
3530 | Evas_Object_Image *o; | ||
3531 | |||
3532 | /* this returns 1 if the internal object data implies that the object was */ | ||
3533 | /* previously fully opaque over the entire rectangle it occupies */ | ||
3534 | o = (Evas_Object_Image *)(obj->object_data); | ||
3535 | if (o->prev.opaque_valid) | ||
3536 | { | ||
3537 | if (!o->prev.opaque) return 0; | ||
3538 | } | ||
3539 | else | ||
3540 | { | ||
3541 | o->prev.opaque = 0; | ||
3542 | o->prev.opaque_valid = 1; | ||
3543 | if ((o->prev.fill.w < 1) || (o->prev.fill.h < 1)) | ||
3544 | return 0; | ||
3545 | if (((o->prev.border.l != 0) || | ||
3546 | (o->prev.border.r != 0) || | ||
3547 | (o->prev.border.t != 0) || | ||
3548 | (o->prev.border.b != 0)) && | ||
3549 | (!o->prev.border.fill)) return 0; | ||
3550 | if (!o->engine_data) return 0; | ||
3551 | o->prev.opaque = 1; | ||
3552 | } | ||
3553 | // FIXME: use proxy | ||
3554 | if (o->prev.source) return 0; /* FIXME: Should go poke at the object */ | ||
3555 | if (obj->prev.usemap) return 0; | ||
3556 | if (obj->prev.render_op == EVAS_RENDER_COPY) return 1; | ||
3557 | if (o->prev.has_alpha) return 0; | ||
3558 | if (obj->prev.render_op != EVAS_RENDER_BLEND) return 0; | ||
3559 | return 1; | ||
3560 | } | ||
3561 | |||
3562 | static int | ||
3563 | evas_object_image_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
3564 | { | ||
3565 | Evas_Object_Image *o; | ||
3566 | DATA32 *data; | ||
3567 | int w, h, stride, iw, ih; | ||
3568 | int a; | ||
3569 | |||
3570 | o = (Evas_Object_Image *)(obj->object_data); | ||
3571 | |||
3572 | x -= obj->cur.cache.clip.x; | ||
3573 | y -= obj->cur.cache.clip.y; | ||
3574 | w = obj->cur.cache.clip.w; | ||
3575 | h = obj->cur.cache.clip.h; | ||
3576 | iw = o->cur.image.w; | ||
3577 | ih = o->cur.image.h; | ||
3578 | |||
3579 | if ((x < 0) || (y < 0) || (x >= w) || (y >= h)) return 0; | ||
3580 | if (!o->cur.has_alpha) return 1; | ||
3581 | |||
3582 | // FIXME: proxy needs to be honored | ||
3583 | if (obj->cur.map) | ||
3584 | { | ||
3585 | x = obj->cur.map->mx; | ||
3586 | y = obj->cur.map->my; | ||
3587 | } | ||
3588 | else | ||
3589 | { | ||
3590 | int bl, br, bt, bb, bsl, bsr, bst, bsb; | ||
3591 | |||
3592 | bl = o->cur.border.l; | ||
3593 | br = o->cur.border.r; | ||
3594 | bt = o->cur.border.t; | ||
3595 | bb = o->cur.border.b; | ||
3596 | if ((bl + br) > iw) | ||
3597 | { | ||
3598 | bl = iw / 2; | ||
3599 | br = iw - bl; | ||
3600 | } | ||
3601 | if ((bl + br) > iw) | ||
3602 | { | ||
3603 | bl = iw / 2; | ||
3604 | br = iw - bl; | ||
3605 | } | ||
3606 | if ((bt + bb) > ih) | ||
3607 | { | ||
3608 | bt = ih / 2; | ||
3609 | bb = ih - bt; | ||
3610 | } | ||
3611 | if ((bt + bb) > ih) | ||
3612 | { | ||
3613 | bt = ih / 2; | ||
3614 | bb = ih - bt; | ||
3615 | } | ||
3616 | if (o->cur.border.scale != 1.0) | ||
3617 | { | ||
3618 | bsl = ((double)bl * o->cur.border.scale); | ||
3619 | bsr = ((double)br * o->cur.border.scale); | ||
3620 | bst = ((double)bt * o->cur.border.scale); | ||
3621 | bsb = ((double)bb * o->cur.border.scale); | ||
3622 | } | ||
3623 | else | ||
3624 | { | ||
3625 | bsl = bl; bsr = br; bst = bt; bsb = bb; | ||
3626 | } | ||
3627 | |||
3628 | w = o->cur.fill.w; | ||
3629 | h = o->cur.fill.h; | ||
3630 | x -= o->cur.fill.x; | ||
3631 | y -= o->cur.fill.y; | ||
3632 | x %= w; | ||
3633 | y %= h; | ||
3634 | |||
3635 | if (x < 0) x += w; | ||
3636 | if (y < 0) y += h; | ||
3637 | |||
3638 | if (o->cur.border.fill != EVAS_BORDER_FILL_DEFAULT) | ||
3639 | { | ||
3640 | if ((x > bsl) && (x < (w - bsr)) && | ||
3641 | (y > bst) && (y < (h - bsb))) | ||
3642 | { | ||
3643 | if (o->cur.border.fill == EVAS_BORDER_FILL_SOLID) return 1; | ||
3644 | return 0; | ||
3645 | } | ||
3646 | } | ||
3647 | |||
3648 | if (x < bsl) x = (x * bl) / bsl; | ||
3649 | else if (x > (w - bsr)) x = iw - (((w - x) * br) / bsr); | ||
3650 | else if ((bsl + bsr) < w) x = bl + (((x - bsl) * (iw - bl - br)) / (w - bsl - bsr)); | ||
3651 | else return 1; | ||
3652 | |||
3653 | if (y < bst) y = (y * bt) / bst; | ||
3654 | else if (y > (h - bsb)) y = ih - (((h - y) * bb) / bsb); | ||
3655 | else if ((bst + bsb) < h) y = bt + (((y - bst) * (ih - bt - bb)) / (h - bst - bsb)); | ||
3656 | else return 1; | ||
3657 | } | ||
3658 | |||
3659 | if (x < 0) x = 0; | ||
3660 | if (y < 0) y = 0; | ||
3661 | if (x >= iw) x = iw - 1; | ||
3662 | if (y >= ih) y = ih - 1; | ||
3663 | |||
3664 | stride = o->cur.image.stride; | ||
3665 | |||
3666 | o->engine_data = obj->layer->evas->engine.func->image_data_get | ||
3667 | (obj->layer->evas->engine.data.output, | ||
3668 | o->engine_data, | ||
3669 | 0, | ||
3670 | &data, | ||
3671 | &o->load_error); | ||
3672 | if (!data) | ||
3673 | return 0; | ||
3674 | |||
3675 | switch (o->cur.cspace) | ||
3676 | { | ||
3677 | case EVAS_COLORSPACE_ARGB8888: | ||
3678 | data = ((DATA32*)(data) + ((y * (stride >> 2)) + x)); | ||
3679 | a = (*((DATA32*)(data)) >> 24) & 0xff; | ||
3680 | break; | ||
3681 | case EVAS_COLORSPACE_RGB565_A5P: | ||
3682 | data = (void*) ((DATA16*)(data) + (h * (stride >> 1))); | ||
3683 | data = (void*) ((DATA8*)(data) + ((y * (stride >> 1)) + x)); | ||
3684 | a = (*((DATA8*)(data))) & 0x1f; | ||
3685 | break; | ||
3686 | default: | ||
3687 | return 1; | ||
3688 | break; | ||
3689 | } | ||
3690 | |||
3691 | return (a != 0); | ||
3692 | } | ||
3693 | |||
3694 | static int | ||
3695 | evas_object_image_has_opaque_rect(Evas_Object *obj) | ||
3696 | { | ||
3697 | Evas_Object_Image *o; | ||
3698 | |||
3699 | o = (Evas_Object_Image *)(obj->object_data); | ||
3700 | if ((obj->cur.map) && (obj->cur.usemap)) return 0; | ||
3701 | if (((o->cur.border.l | o->cur.border.r | o->cur.border.t | o->cur.border.b) != 0) && | ||
3702 | (o->cur.border.fill == EVAS_BORDER_FILL_SOLID) && | ||
3703 | (obj->cur.render_op == EVAS_RENDER_BLEND) && | ||
3704 | (obj->cur.cache.clip.a == 255) && | ||
3705 | (o->cur.fill.x == 0) && | ||
3706 | (o->cur.fill.y == 0) && | ||
3707 | (o->cur.fill.w == obj->cur.geometry.w) && | ||
3708 | (o->cur.fill.h == obj->cur.geometry.h) | ||
3709 | ) return 1; | ||
3710 | return 0; | ||
3711 | } | ||
3712 | |||
3713 | static int | ||
3714 | evas_object_image_get_opaque_rect(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) | ||
3715 | { | ||
3716 | Evas_Object_Image *o; | ||
3717 | |||
3718 | o = (Evas_Object_Image *)(obj->object_data); | ||
3719 | if (o->cur.border.scale == 1.0) | ||
3720 | { | ||
3721 | *x = obj->cur.geometry.x + o->cur.border.l; | ||
3722 | *y = obj->cur.geometry.y + o->cur.border.t; | ||
3723 | *w = obj->cur.geometry.w - (o->cur.border.l + o->cur.border.r); | ||
3724 | if (*w < 0) *w = 0; | ||
3725 | *h = obj->cur.geometry.h - (o->cur.border.t + o->cur.border.b); | ||
3726 | if (*h < 0) *h = 0; | ||
3727 | } | ||
3728 | else | ||
3729 | { | ||
3730 | *x = obj->cur.geometry.x + (o->cur.border.l * o->cur.border.scale); | ||
3731 | *y = obj->cur.geometry.y + (o->cur.border.t * o->cur.border.scale); | ||
3732 | *w = obj->cur.geometry.w - ((o->cur.border.l * o->cur.border.scale) + (o->cur.border.r * o->cur.border.scale)); | ||
3733 | if (*w < 0) *w = 0; | ||
3734 | *h = obj->cur.geometry.h - ((o->cur.border.t * o->cur.border.scale) + (o->cur.border.b * o->cur.border.scale)); | ||
3735 | if (*h < 0) *h = 0; | ||
3736 | } | ||
3737 | return 1; | ||
3738 | } | ||
3739 | |||
3740 | static int | ||
3741 | evas_object_image_can_map(Evas_Object *obj __UNUSED__) | ||
3742 | { | ||
3743 | return 1; | ||
3744 | } | ||
3745 | |||
3746 | static void * | ||
3747 | evas_object_image_data_convert_internal(Evas_Object_Image *o, void *data, Evas_Colorspace to_cspace) | ||
3748 | { | ||
3749 | void *out = NULL; | ||
3750 | |||
3751 | if (!data) | ||
3752 | return NULL; | ||
3753 | |||
3754 | switch (o->cur.cspace) | ||
3755 | { | ||
3756 | case EVAS_COLORSPACE_ARGB8888: | ||
3757 | out = evas_common_convert_argb8888_to(data, | ||
3758 | o->cur.image.w, | ||
3759 | o->cur.image.h, | ||
3760 | o->cur.image.stride >> 2, | ||
3761 | o->cur.has_alpha, | ||
3762 | to_cspace); | ||
3763 | break; | ||
3764 | case EVAS_COLORSPACE_RGB565_A5P: | ||
3765 | out = evas_common_convert_rgb565_a5p_to(data, | ||
3766 | o->cur.image.w, | ||
3767 | o->cur.image.h, | ||
3768 | o->cur.image.stride >> 1, | ||
3769 | o->cur.has_alpha, | ||
3770 | to_cspace); | ||
3771 | break; | ||
3772 | case EVAS_COLORSPACE_YCBCR422601_PL: | ||
3773 | fprintf(stderr, "EVAS_COLORSPACE_YCBCR422601_PL:\n"); | ||
3774 | out = evas_common_convert_yuv_422_601_to(data, | ||
3775 | o->cur.image.w, | ||
3776 | o->cur.image.h, | ||
3777 | to_cspace); | ||
3778 | break; | ||
3779 | case EVAS_COLORSPACE_YCBCR422P601_PL: | ||
3780 | out = evas_common_convert_yuv_422P_601_to(data, | ||
3781 | o->cur.image.w, | ||
3782 | o->cur.image.h, | ||
3783 | to_cspace); | ||
3784 | break; | ||
3785 | case EVAS_COLORSPACE_YCBCR420NV12601_PL: | ||
3786 | out = evas_common_convert_yuv_420_601_to(data, | ||
3787 | o->cur.image.w, | ||
3788 | o->cur.image.h, | ||
3789 | to_cspace); | ||
3790 | break; | ||
3791 | case EVAS_COLORSPACE_YCBCR420TM12601_PL: | ||
3792 | out = evas_common_convert_yuv_420T_601_to(data, | ||
3793 | o->cur.image.w, | ||
3794 | o->cur.image.h, | ||
3795 | to_cspace); | ||
3796 | break; | ||
3797 | default: | ||
3798 | fprintf(stderr, "unknow colorspace: %i\n", o->cur.cspace); | ||
3799 | break; | ||
3800 | } | ||
3801 | |||
3802 | return out; | ||
3803 | } | ||
3804 | |||
3805 | static void | ||
3806 | evas_object_image_filled_resize_listener(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *einfo __UNUSED__) | ||
3807 | { | ||
3808 | Evas_Coord w, h; | ||
3809 | Evas_Object_Image *o; | ||
3810 | |||
3811 | o = obj->object_data; | ||
3812 | evas_object_geometry_get(obj, NULL, NULL, &w, &h); | ||
3813 | evas_object_image_fill_set(obj, 0, 0, w, h); | ||
3814 | } | ||
3815 | |||
3816 | |||
3817 | Eina_Bool | ||
3818 | _evas_object_image_preloading_get(const Evas_Object *obj) | ||
3819 | { | ||
3820 | Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data); | ||
3821 | if (!o) return EINA_FALSE; | ||
3822 | MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE); | ||
3823 | return EINA_FALSE; | ||
3824 | MAGIC_CHECK_END(); | ||
3825 | return o->preloading; | ||
3826 | } | ||
3827 | |||
3828 | void | ||
3829 | _evas_object_image_preloading_set(Evas_Object *obj, Eina_Bool preloading) | ||
3830 | { | ||
3831 | Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data); | ||
3832 | o->preloading = preloading; | ||
3833 | } | ||
3834 | |||
3835 | void | ||
3836 | _evas_object_image_preloading_check(Evas_Object *obj) | ||
3837 | { | ||
3838 | Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data); | ||
3839 | if (obj->layer->evas->engine.func->image_load_error_get) | ||
3840 | o->load_error = obj->layer->evas->engine.func->image_load_error_get | ||
3841 | (obj->layer->evas->engine.data.output, o->engine_data); | ||
3842 | } | ||
3843 | |||
3844 | Evas_Object * | ||
3845 | _evas_object_image_video_parent_get(Evas_Object *obj) | ||
3846 | { | ||
3847 | Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data); | ||
3848 | |||
3849 | return o->video_surface ? o->video.parent : NULL; | ||
3850 | } | ||
3851 | |||
3852 | void | ||
3853 | _evas_object_image_video_overlay_show(Evas_Object *obj) | ||
3854 | { | ||
3855 | Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data); | ||
3856 | |||
3857 | if (obj->cur.cache.clip.x != obj->prev.cache.clip.x || | ||
3858 | obj->cur.cache.clip.y != obj->prev.cache.clip.y || | ||
3859 | o->created || !o->video_visible) | ||
3860 | o->video.move(o->video.data, obj, &o->video, obj->cur.cache.clip.x, obj->cur.cache.clip.y); | ||
3861 | if (obj->cur.cache.clip.w != obj->prev.cache.clip.w || | ||
3862 | obj->cur.cache.clip.h != obj->prev.cache.clip.h || | ||
3863 | o->created || !o->video_visible) | ||
3864 | o->video.resize(o->video.data, obj, &o->video, obj->cur.cache.clip.w, obj->cur.cache.clip.h); | ||
3865 | if (!o->video_visible || o->created) | ||
3866 | { | ||
3867 | o->video.show(o->video.data, obj, &o->video); | ||
3868 | } | ||
3869 | else | ||
3870 | { | ||
3871 | /* Cancel dirty on the image */ | ||
3872 | Eina_Rectangle *r; | ||
3873 | |||
3874 | o->dirty_pixels = 0; | ||
3875 | EINA_LIST_FREE(o->pixel_updates, r) | ||
3876 | eina_rectangle_free(r); | ||
3877 | } | ||
3878 | o->video_visible = EINA_TRUE; | ||
3879 | o->created = EINA_FALSE; | ||
3880 | } | ||
3881 | |||
3882 | void | ||
3883 | _evas_object_image_video_overlay_hide(Evas_Object *obj) | ||
3884 | { | ||
3885 | Evas_Object_Image *o = (Evas_Object_Image *)(obj->object_data); | ||
3886 | |||
3887 | if (o->video_visible || o->created) | ||
3888 | o->video.hide(o->video.data, obj, &o->video); | ||
3889 | if (evas_object_is_visible(obj)) | ||
3890 | o->video.update_pixels(o->video.data, obj, &o->video); | ||
3891 | o->video_visible = EINA_FALSE; | ||
3892 | o->created = EINA_FALSE; | ||
3893 | } | ||
3894 | |||
3895 | /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/ | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_inform.c b/libraries/evas/src/lib/canvas/evas_object_inform.c new file mode 100644 index 0000000..bc09eb9 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_inform.c | |||
@@ -0,0 +1,79 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* local calls */ | ||
5 | |||
6 | void | ||
7 | evas_object_inform_call_show(Evas_Object *obj) | ||
8 | { | ||
9 | _evas_object_event_new(); | ||
10 | |||
11 | evas_object_event_callback_call(obj, EVAS_CALLBACK_SHOW, NULL); | ||
12 | _evas_post_event_callback_call(obj->layer->evas); | ||
13 | } | ||
14 | |||
15 | void | ||
16 | evas_object_inform_call_hide(Evas_Object *obj) | ||
17 | { | ||
18 | _evas_object_event_new(); | ||
19 | |||
20 | evas_object_event_callback_call(obj, EVAS_CALLBACK_HIDE, NULL); | ||
21 | _evas_post_event_callback_call(obj->layer->evas); | ||
22 | } | ||
23 | |||
24 | void | ||
25 | evas_object_inform_call_move(Evas_Object *obj) | ||
26 | { | ||
27 | _evas_object_event_new(); | ||
28 | |||
29 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOVE, NULL); | ||
30 | _evas_post_event_callback_call(obj->layer->evas); | ||
31 | } | ||
32 | |||
33 | void | ||
34 | evas_object_inform_call_resize(Evas_Object *obj) | ||
35 | { | ||
36 | _evas_object_event_new(); | ||
37 | |||
38 | evas_object_event_callback_call(obj, EVAS_CALLBACK_RESIZE, NULL); | ||
39 | _evas_post_event_callback_call(obj->layer->evas); | ||
40 | } | ||
41 | |||
42 | void | ||
43 | evas_object_inform_call_restack(Evas_Object *obj) | ||
44 | { | ||
45 | _evas_object_event_new(); | ||
46 | |||
47 | evas_object_event_callback_call(obj, EVAS_CALLBACK_RESTACK, NULL); | ||
48 | _evas_post_event_callback_call(obj->layer->evas); | ||
49 | } | ||
50 | |||
51 | void | ||
52 | evas_object_inform_call_changed_size_hints(Evas_Object *obj) | ||
53 | { | ||
54 | _evas_object_event_new(); | ||
55 | |||
56 | evas_object_event_callback_call(obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, NULL); | ||
57 | _evas_post_event_callback_call(obj->layer->evas); | ||
58 | } | ||
59 | |||
60 | void | ||
61 | evas_object_inform_call_image_preloaded(Evas_Object *obj) | ||
62 | { | ||
63 | if (!_evas_object_image_preloading_get(obj)) return; | ||
64 | _evas_object_image_preloading_check(obj); | ||
65 | _evas_object_image_preloading_set(obj, 0); | ||
66 | _evas_object_event_new(); | ||
67 | |||
68 | evas_object_event_callback_call(obj, EVAS_CALLBACK_IMAGE_PRELOADED, NULL); | ||
69 | _evas_post_event_callback_call(obj->layer->evas); | ||
70 | } | ||
71 | |||
72 | void | ||
73 | evas_object_inform_call_image_unloaded(Evas_Object *obj) | ||
74 | { | ||
75 | _evas_object_event_new(); | ||
76 | |||
77 | evas_object_event_callback_call(obj, EVAS_CALLBACK_IMAGE_UNLOADED, NULL); | ||
78 | _evas_post_event_callback_call(obj->layer->evas); | ||
79 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_intercept.c b/libraries/evas/src/lib/canvas/evas_object_intercept.c new file mode 100644 index 0000000..c3e5e24 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_intercept.c | |||
@@ -0,0 +1,625 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* local calls */ | ||
5 | |||
6 | static void evas_object_intercept_init(Evas_Object *obj); | ||
7 | static void evas_object_intercept_deinit(Evas_Object *obj); | ||
8 | |||
9 | static void | ||
10 | evas_object_intercept_init(Evas_Object *obj) | ||
11 | { | ||
12 | /* MEM OK */ | ||
13 | if (!obj->interceptors) | ||
14 | obj->interceptors = evas_mem_calloc(sizeof(Evas_Intercept_Func)); | ||
15 | } | ||
16 | |||
17 | static void | ||
18 | evas_object_intercept_deinit(Evas_Object *obj) | ||
19 | { | ||
20 | /* MEM OK */ | ||
21 | if (!obj->interceptors) return; | ||
22 | if ((obj->interceptors->show.func) || | ||
23 | (obj->interceptors->hide.func) || | ||
24 | (obj->interceptors->move.func) || | ||
25 | (obj->interceptors->resize.func) || | ||
26 | (obj->interceptors->raise.func) || | ||
27 | (obj->interceptors->lower.func) || | ||
28 | (obj->interceptors->stack_above.func) || | ||
29 | (obj->interceptors->stack_below.func) || | ||
30 | (obj->interceptors->layer_set.func) || | ||
31 | (obj->interceptors->color_set.func) || | ||
32 | (obj->interceptors->clip_set.func) || | ||
33 | (obj->interceptors->clip_unset.func)) | ||
34 | return; | ||
35 | free(obj->interceptors); | ||
36 | obj->interceptors = NULL; | ||
37 | } | ||
38 | |||
39 | /* private calls */ | ||
40 | |||
41 | void | ||
42 | evas_object_intercept_cleanup(Evas_Object *obj) | ||
43 | { | ||
44 | /* MEM OK */ | ||
45 | if (obj->interceptors) free(obj->interceptors); | ||
46 | } | ||
47 | |||
48 | int | ||
49 | evas_object_intercept_call_show(Evas_Object *obj) | ||
50 | { | ||
51 | /* MEM OK */ | ||
52 | int ret; | ||
53 | |||
54 | if (!obj->interceptors) return 0; | ||
55 | if (obj->intercepted) return 0; | ||
56 | obj->intercepted = 1; | ||
57 | ret = !!(obj->interceptors->show.func); | ||
58 | if (obj->interceptors->show.func) | ||
59 | obj->interceptors->show.func(obj->interceptors->show.data, obj); | ||
60 | obj->intercepted = 0; | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | int | ||
65 | evas_object_intercept_call_hide(Evas_Object *obj) | ||
66 | { | ||
67 | /* MEM OK */ | ||
68 | int ret; | ||
69 | |||
70 | if (!obj->interceptors) return 0; | ||
71 | if (obj->intercepted) return 0; | ||
72 | obj->intercepted = 1; | ||
73 | ret = !!(obj->interceptors->hide.func); | ||
74 | if (obj->interceptors->hide.func) | ||
75 | obj->interceptors->hide.func(obj->interceptors->hide.data, obj); | ||
76 | obj->intercepted = 0; | ||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | int | ||
81 | evas_object_intercept_call_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
82 | { | ||
83 | /* MEM OK */ | ||
84 | int ret; | ||
85 | |||
86 | if (!obj->interceptors) return 0; | ||
87 | if (obj->intercepted) return 0; | ||
88 | obj->intercepted = 1; | ||
89 | ret = !!(obj->interceptors->move.func); | ||
90 | if (obj->interceptors->move.func) | ||
91 | obj->interceptors->move.func(obj->interceptors->move.data, obj, x, y); | ||
92 | obj->intercepted = 0; | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | int | ||
97 | evas_object_intercept_call_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) | ||
98 | { | ||
99 | /* MEM OK */ | ||
100 | int ret; | ||
101 | |||
102 | if (!obj->interceptors) return 0; | ||
103 | if (obj->intercepted) return 0; | ||
104 | obj->intercepted = 1; | ||
105 | ret = !!(obj->interceptors->resize.func); | ||
106 | if (obj->interceptors->resize.func) | ||
107 | obj->interceptors->resize.func(obj->interceptors->resize.data, obj, w, h); | ||
108 | obj->intercepted = 0; | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | int | ||
113 | evas_object_intercept_call_raise(Evas_Object *obj) | ||
114 | { | ||
115 | /* MEM OK */ | ||
116 | int ret; | ||
117 | |||
118 | if (!obj->interceptors) return 0; | ||
119 | if (obj->intercepted) return 0; | ||
120 | obj->intercepted = 1; | ||
121 | ret = !!(obj->interceptors->raise.func); | ||
122 | if (obj->interceptors->raise.func) | ||
123 | obj->interceptors->raise.func(obj->interceptors->raise.data, obj); | ||
124 | obj->intercepted = 0; | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | int | ||
129 | evas_object_intercept_call_lower(Evas_Object *obj) | ||
130 | { | ||
131 | /* MEM OK */ | ||
132 | int ret; | ||
133 | |||
134 | if (!obj->interceptors) return 0; | ||
135 | if (obj->intercepted) return 0; | ||
136 | obj->intercepted = 1; | ||
137 | ret = !!(obj->interceptors->lower.func); | ||
138 | if (obj->interceptors->lower.func) | ||
139 | obj->interceptors->lower.func(obj->interceptors->lower.data, obj); | ||
140 | obj->intercepted = 0; | ||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | int | ||
145 | evas_object_intercept_call_stack_above(Evas_Object *obj, Evas_Object *above) | ||
146 | { | ||
147 | /* MEM OK */ | ||
148 | int ret; | ||
149 | |||
150 | if (!obj->interceptors) return 0; | ||
151 | if (obj->intercepted) return 0; | ||
152 | obj->intercepted = 1; | ||
153 | ret = !!(obj->interceptors->stack_above.func); | ||
154 | if (obj->interceptors->stack_above.func) | ||
155 | obj->interceptors->stack_above.func(obj->interceptors->stack_above.data, obj, above); | ||
156 | obj->intercepted = 0; | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | int | ||
161 | evas_object_intercept_call_stack_below(Evas_Object *obj, Evas_Object *below) | ||
162 | { | ||
163 | /* MEM OK */ | ||
164 | int ret; | ||
165 | |||
166 | if (!obj->interceptors) return 0; | ||
167 | if (obj->intercepted) return 0; | ||
168 | obj->intercepted = 1; | ||
169 | ret = !!(obj->interceptors->stack_below.func); | ||
170 | if (obj->interceptors->stack_below.func) | ||
171 | obj->interceptors->stack_below.func(obj->interceptors->stack_below.data, obj, below); | ||
172 | obj->intercepted = 0; | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | int | ||
177 | evas_object_intercept_call_layer_set(Evas_Object *obj, int l) | ||
178 | { | ||
179 | /* MEM OK */ | ||
180 | int ret; | ||
181 | |||
182 | if (!obj->interceptors) return 0; | ||
183 | if (obj->intercepted) return 0; | ||
184 | obj->intercepted = 1; | ||
185 | ret = !!(obj->interceptors->layer_set.func); | ||
186 | if (obj->interceptors->layer_set.func) | ||
187 | obj->interceptors->layer_set.func(obj->interceptors->layer_set.data, obj, l); | ||
188 | obj->intercepted = 0; | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | int | ||
193 | evas_object_intercept_call_color_set(Evas_Object *obj, int r, int g, int b, int a) | ||
194 | { | ||
195 | /* MEM OK */ | ||
196 | int ret; | ||
197 | |||
198 | if (!obj->interceptors) return 0; | ||
199 | if (obj->intercepted) return 0; | ||
200 | obj->intercepted = 1; | ||
201 | ret = !!(obj->interceptors->color_set.func); | ||
202 | if (obj->interceptors->color_set.func) | ||
203 | obj->interceptors->color_set.func(obj->interceptors->color_set.data, obj, r, g, b, a); | ||
204 | obj->intercepted = 0; | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | int | ||
209 | evas_object_intercept_call_clip_set(Evas_Object *obj, Evas_Object *clip) | ||
210 | { | ||
211 | /* MEM OK */ | ||
212 | int ret; | ||
213 | |||
214 | if (!obj->interceptors) return 0; | ||
215 | if (obj->intercepted) return 0; | ||
216 | obj->intercepted = 1; | ||
217 | ret = !!(obj->interceptors->clip_set.func); | ||
218 | if (obj->interceptors->clip_set.func) | ||
219 | obj->interceptors->clip_set.func(obj->interceptors->clip_set.data, obj, clip); | ||
220 | obj->intercepted = 0; | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | int | ||
225 | evas_object_intercept_call_clip_unset(Evas_Object *obj) | ||
226 | { | ||
227 | /* MEM OK */ | ||
228 | int ret; | ||
229 | |||
230 | if (!obj->interceptors) return 0; | ||
231 | if (obj->intercepted) return 0; | ||
232 | obj->intercepted = 1; | ||
233 | ret = !!(obj->interceptors->clip_unset.func); | ||
234 | if (obj->interceptors->clip_unset.func) | ||
235 | obj->interceptors->clip_unset.func(obj->interceptors->clip_unset.data, obj); | ||
236 | obj->intercepted = 0; | ||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | /* public calls */ | ||
241 | |||
242 | EAPI void | ||
243 | evas_object_intercept_show_callback_add(Evas_Object *obj, Evas_Object_Intercept_Show_Cb func, const void *data) | ||
244 | { | ||
245 | /* MEM OK */ | ||
246 | |||
247 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
248 | return; | ||
249 | MAGIC_CHECK_END(); | ||
250 | if (!func) return; | ||
251 | evas_object_intercept_init(obj); | ||
252 | if (!obj->interceptors) return; | ||
253 | obj->interceptors->show.func = func; | ||
254 | obj->interceptors->show.data = (void *)data; | ||
255 | } | ||
256 | |||
257 | EAPI void * | ||
258 | evas_object_intercept_show_callback_del(Evas_Object *obj, Evas_Object_Intercept_Show_Cb func) | ||
259 | { | ||
260 | /* MEM OK */ | ||
261 | void *data; | ||
262 | |||
263 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
264 | return NULL; | ||
265 | MAGIC_CHECK_END(); | ||
266 | if (!func) return NULL; | ||
267 | if (!obj->interceptors) return NULL; | ||
268 | obj->interceptors->show.func = NULL; | ||
269 | data = obj->interceptors->show.data; | ||
270 | obj->interceptors->show.data = NULL; | ||
271 | evas_object_intercept_deinit(obj); | ||
272 | return data; | ||
273 | } | ||
274 | |||
275 | EAPI void | ||
276 | evas_object_intercept_hide_callback_add(Evas_Object *obj, Evas_Object_Intercept_Hide_Cb func, const void *data) | ||
277 | { | ||
278 | /* MEM OK */ | ||
279 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
280 | return; | ||
281 | MAGIC_CHECK_END(); | ||
282 | if (!func) return; | ||
283 | evas_object_intercept_init(obj); | ||
284 | if (!obj->interceptors) return; | ||
285 | obj->interceptors->hide.func = func; | ||
286 | obj->interceptors->hide.data = (void *)data; | ||
287 | } | ||
288 | |||
289 | EAPI void * | ||
290 | evas_object_intercept_hide_callback_del(Evas_Object *obj, Evas_Object_Intercept_Hide_Cb func) | ||
291 | { | ||
292 | /* MEM OK */ | ||
293 | void *data; | ||
294 | |||
295 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
296 | return NULL; | ||
297 | MAGIC_CHECK_END(); | ||
298 | if (!func) return NULL; | ||
299 | if (!obj->interceptors) return NULL; | ||
300 | obj->interceptors->hide.func = NULL; | ||
301 | data = obj->interceptors->hide.data; | ||
302 | obj->interceptors->hide.data = NULL; | ||
303 | evas_object_intercept_deinit(obj); | ||
304 | return data; | ||
305 | } | ||
306 | |||
307 | EAPI void | ||
308 | evas_object_intercept_move_callback_add(Evas_Object *obj, Evas_Object_Intercept_Move_Cb func, const void *data) | ||
309 | { | ||
310 | /* MEM OK */ | ||
311 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
312 | return; | ||
313 | MAGIC_CHECK_END(); | ||
314 | if (!func) return; | ||
315 | evas_object_intercept_init(obj); | ||
316 | if (!obj->interceptors) return; | ||
317 | obj->interceptors->move.func = func; | ||
318 | obj->interceptors->move.data = (void *)data; | ||
319 | } | ||
320 | |||
321 | EAPI void * | ||
322 | evas_object_intercept_move_callback_del(Evas_Object *obj, Evas_Object_Intercept_Move_Cb func) | ||
323 | { | ||
324 | /* MEM OK */ | ||
325 | void *data; | ||
326 | |||
327 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
328 | return NULL; | ||
329 | MAGIC_CHECK_END(); | ||
330 | if (!func) return NULL; | ||
331 | if (!obj->interceptors) return NULL; | ||
332 | obj->interceptors->move.func = NULL; | ||
333 | data = obj->interceptors->move.data; | ||
334 | obj->interceptors->move.data = NULL; | ||
335 | evas_object_intercept_deinit(obj); | ||
336 | return data; | ||
337 | } | ||
338 | |||
339 | EAPI void | ||
340 | evas_object_intercept_resize_callback_add(Evas_Object *obj, Evas_Object_Intercept_Resize_Cb func, const void *data) | ||
341 | { | ||
342 | /* MEM OK */ | ||
343 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
344 | return; | ||
345 | MAGIC_CHECK_END(); | ||
346 | if (!func) return; | ||
347 | evas_object_intercept_init(obj); | ||
348 | if (!obj->interceptors) return; | ||
349 | obj->interceptors->resize.func = func; | ||
350 | obj->interceptors->resize.data = (void *)data; | ||
351 | } | ||
352 | |||
353 | EAPI void * | ||
354 | evas_object_intercept_resize_callback_del(Evas_Object *obj, Evas_Object_Intercept_Resize_Cb func) | ||
355 | { | ||
356 | /* MEM OK */ | ||
357 | void *data; | ||
358 | |||
359 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
360 | return NULL; | ||
361 | MAGIC_CHECK_END(); | ||
362 | if (!func) return NULL; | ||
363 | if (!obj->interceptors) return NULL; | ||
364 | obj->interceptors->resize.func = NULL; | ||
365 | data = obj->interceptors->resize.data; | ||
366 | obj->interceptors->resize.data = NULL; | ||
367 | evas_object_intercept_deinit(obj); | ||
368 | return data; | ||
369 | } | ||
370 | |||
371 | EAPI void | ||
372 | evas_object_intercept_raise_callback_add(Evas_Object *obj, Evas_Object_Intercept_Raise_Cb func, const void *data) | ||
373 | { | ||
374 | /* MEM OK */ | ||
375 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
376 | return; | ||
377 | MAGIC_CHECK_END(); | ||
378 | if (!func) return; | ||
379 | evas_object_intercept_init(obj); | ||
380 | if (!obj->interceptors) return; | ||
381 | obj->interceptors->raise.func = func; | ||
382 | obj->interceptors->raise.data = (void *)data; | ||
383 | } | ||
384 | |||
385 | EAPI void * | ||
386 | evas_object_intercept_raise_callback_del(Evas_Object *obj, Evas_Object_Intercept_Raise_Cb func) | ||
387 | { | ||
388 | /* MEM OK */ | ||
389 | void *data; | ||
390 | |||
391 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
392 | return NULL; | ||
393 | MAGIC_CHECK_END(); | ||
394 | if (!func) return NULL; | ||
395 | if (!obj->interceptors) return NULL; | ||
396 | obj->interceptors->raise.func = NULL; | ||
397 | data = obj->interceptors->raise.data; | ||
398 | obj->interceptors->raise.data = NULL; | ||
399 | evas_object_intercept_deinit(obj); | ||
400 | return data; | ||
401 | } | ||
402 | |||
403 | EAPI void | ||
404 | evas_object_intercept_lower_callback_add(Evas_Object *obj, Evas_Object_Intercept_Lower_Cb func, const void *data) | ||
405 | { | ||
406 | /* MEM OK */ | ||
407 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
408 | return; | ||
409 | MAGIC_CHECK_END(); | ||
410 | if (!func) return; | ||
411 | evas_object_intercept_init(obj); | ||
412 | if (!obj->interceptors) return; | ||
413 | obj->interceptors->lower.func = func; | ||
414 | obj->interceptors->lower.data = (void *)data; | ||
415 | } | ||
416 | |||
417 | EAPI void * | ||
418 | evas_object_intercept_lower_callback_del(Evas_Object *obj, Evas_Object_Intercept_Lower_Cb func) | ||
419 | { | ||
420 | /* MEM OK */ | ||
421 | void *data; | ||
422 | |||
423 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
424 | return NULL; | ||
425 | MAGIC_CHECK_END(); | ||
426 | if (!func) return NULL; | ||
427 | if (!obj->interceptors) return NULL; | ||
428 | obj->interceptors->lower.func = NULL; | ||
429 | data = obj->interceptors->lower.data; | ||
430 | obj->interceptors->lower.data = NULL; | ||
431 | evas_object_intercept_deinit(obj); | ||
432 | return data; | ||
433 | } | ||
434 | |||
435 | EAPI void | ||
436 | evas_object_intercept_stack_above_callback_add(Evas_Object *obj, Evas_Object_Intercept_Stack_Above_Cb func, const void *data) | ||
437 | { | ||
438 | /* MEM OK */ | ||
439 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
440 | return; | ||
441 | MAGIC_CHECK_END(); | ||
442 | if (!func) return; | ||
443 | evas_object_intercept_init(obj); | ||
444 | if (!obj->interceptors) return; | ||
445 | obj->interceptors->stack_above.func = func; | ||
446 | obj->interceptors->stack_above.data = (void *)data; | ||
447 | } | ||
448 | |||
449 | EAPI void * | ||
450 | evas_object_intercept_stack_above_callback_del(Evas_Object *obj, Evas_Object_Intercept_Stack_Above_Cb func) | ||
451 | { | ||
452 | /* MEM OK */ | ||
453 | void *data; | ||
454 | |||
455 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
456 | return NULL; | ||
457 | MAGIC_CHECK_END(); | ||
458 | if (!func) return NULL; | ||
459 | if (!obj->interceptors) return NULL; | ||
460 | obj->interceptors->stack_above.func = NULL; | ||
461 | data = obj->interceptors->stack_above.data; | ||
462 | obj->interceptors->stack_above.data = NULL; | ||
463 | evas_object_intercept_deinit(obj); | ||
464 | return data; | ||
465 | } | ||
466 | |||
467 | EAPI void | ||
468 | evas_object_intercept_stack_below_callback_add(Evas_Object *obj, Evas_Object_Intercept_Stack_Below_Cb func, const void *data) | ||
469 | { | ||
470 | /* MEM OK */ | ||
471 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
472 | return; | ||
473 | MAGIC_CHECK_END(); | ||
474 | if (!func) return; | ||
475 | evas_object_intercept_init(obj); | ||
476 | if (!obj->interceptors) return; | ||
477 | obj->interceptors->stack_below.func = func; | ||
478 | obj->interceptors->stack_below.data = (void *)data; | ||
479 | } | ||
480 | |||
481 | EAPI void * | ||
482 | evas_object_intercept_stack_below_callback_del(Evas_Object *obj, Evas_Object_Intercept_Stack_Below_Cb func) | ||
483 | { | ||
484 | /* MEM OK */ | ||
485 | void *data; | ||
486 | |||
487 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
488 | return NULL; | ||
489 | MAGIC_CHECK_END(); | ||
490 | if (!func) return NULL; | ||
491 | if (!obj->interceptors) return NULL; | ||
492 | obj->interceptors->stack_below.func = NULL; | ||
493 | data = obj->interceptors->stack_below.data; | ||
494 | obj->interceptors->stack_below.data = NULL; | ||
495 | evas_object_intercept_deinit(obj); | ||
496 | return data; | ||
497 | } | ||
498 | |||
499 | EAPI void | ||
500 | evas_object_intercept_layer_set_callback_add(Evas_Object *obj, Evas_Object_Intercept_Layer_Set_Cb func, const void *data) | ||
501 | { | ||
502 | /* MEM OK */ | ||
503 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
504 | return; | ||
505 | MAGIC_CHECK_END(); | ||
506 | if (!func) return; | ||
507 | evas_object_intercept_init(obj); | ||
508 | if (!obj->interceptors) return; | ||
509 | obj->interceptors->layer_set.func = func; | ||
510 | obj->interceptors->layer_set.data = (void *)data; | ||
511 | } | ||
512 | |||
513 | EAPI void * | ||
514 | evas_object_intercept_layer_set_callback_del(Evas_Object *obj, Evas_Object_Intercept_Layer_Set_Cb func) | ||
515 | { | ||
516 | /* MEM OK */ | ||
517 | void *data; | ||
518 | |||
519 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
520 | return NULL; | ||
521 | MAGIC_CHECK_END(); | ||
522 | if (!func) return NULL; | ||
523 | if (!obj->interceptors) return NULL; | ||
524 | obj->interceptors->layer_set.func = NULL; | ||
525 | data = obj->interceptors->layer_set.data; | ||
526 | obj->interceptors->layer_set.data = NULL; | ||
527 | evas_object_intercept_deinit(obj); | ||
528 | return data; | ||
529 | } | ||
530 | |||
531 | EAPI void | ||
532 | evas_object_intercept_color_set_callback_add(Evas_Object *obj, Evas_Object_Intercept_Color_Set_Cb func, const void *data) | ||
533 | { | ||
534 | /* MEM OK */ | ||
535 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
536 | return; | ||
537 | MAGIC_CHECK_END(); | ||
538 | if (!func) return; | ||
539 | evas_object_intercept_init(obj); | ||
540 | if (!obj->interceptors) return; | ||
541 | obj->interceptors->color_set.func = func; | ||
542 | obj->interceptors->color_set.data = (void *)data; | ||
543 | } | ||
544 | |||
545 | EAPI void * | ||
546 | evas_object_intercept_color_set_callback_del(Evas_Object *obj, Evas_Object_Intercept_Color_Set_Cb func) | ||
547 | { | ||
548 | /* MEM OK */ | ||
549 | void *data; | ||
550 | |||
551 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
552 | return NULL; | ||
553 | MAGIC_CHECK_END(); | ||
554 | if (!func) return NULL; | ||
555 | if (!obj->interceptors) return NULL; | ||
556 | obj->interceptors->color_set.func = NULL; | ||
557 | data = obj->interceptors->color_set.data; | ||
558 | obj->interceptors->color_set.data = NULL; | ||
559 | evas_object_intercept_deinit(obj); | ||
560 | return data; | ||
561 | } | ||
562 | |||
563 | EAPI void | ||
564 | evas_object_intercept_clip_set_callback_add(Evas_Object *obj, Evas_Object_Intercept_Clip_Set_Cb func, const void *data) | ||
565 | { | ||
566 | /* MEM OK */ | ||
567 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
568 | return; | ||
569 | MAGIC_CHECK_END(); | ||
570 | if (!func) return; | ||
571 | evas_object_intercept_init(obj); | ||
572 | if (!obj->interceptors) return; | ||
573 | obj->interceptors->clip_set.func = func; | ||
574 | obj->interceptors->clip_set.data = (void *)data; | ||
575 | } | ||
576 | |||
577 | EAPI void * | ||
578 | evas_object_intercept_clip_set_callback_del(Evas_Object *obj, Evas_Object_Intercept_Clip_Set_Cb func) | ||
579 | { | ||
580 | /* MEM OK */ | ||
581 | void *data; | ||
582 | |||
583 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
584 | return NULL; | ||
585 | MAGIC_CHECK_END(); | ||
586 | if (!func) return NULL; | ||
587 | if (!obj->interceptors) return NULL; | ||
588 | obj->interceptors->clip_set.func = NULL; | ||
589 | data = obj->interceptors->clip_set.data; | ||
590 | obj->interceptors->clip_set.data = NULL; | ||
591 | evas_object_intercept_deinit(obj); | ||
592 | return data; | ||
593 | } | ||
594 | |||
595 | EAPI void | ||
596 | evas_object_intercept_clip_unset_callback_add(Evas_Object *obj, Evas_Object_Intercept_Clip_Unset_Cb func, const void *data) | ||
597 | { | ||
598 | /* MEM OK */ | ||
599 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
600 | return; | ||
601 | MAGIC_CHECK_END(); | ||
602 | if (!func) return; | ||
603 | evas_object_intercept_init(obj); | ||
604 | if (!obj->interceptors) return; | ||
605 | obj->interceptors->clip_unset.func = func; | ||
606 | obj->interceptors->clip_unset.data = (void *)data; | ||
607 | } | ||
608 | |||
609 | EAPI void * | ||
610 | evas_object_intercept_clip_unset_callback_del(Evas_Object *obj, Evas_Object_Intercept_Clip_Unset_Cb func) | ||
611 | { | ||
612 | /* MEM OK */ | ||
613 | void *data; | ||
614 | |||
615 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
616 | return NULL; | ||
617 | MAGIC_CHECK_END(); | ||
618 | if (!func) return NULL; | ||
619 | if (!obj->interceptors) return NULL; | ||
620 | obj->interceptors->clip_unset.func = NULL; | ||
621 | data = obj->interceptors->clip_unset.data; | ||
622 | obj->interceptors->clip_unset.data = NULL; | ||
623 | evas_object_intercept_deinit(obj); | ||
624 | return data; | ||
625 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_line.c b/libraries/evas/src/lib/canvas/evas_object_line.c new file mode 100644 index 0000000..b09a6e2 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_line.c | |||
@@ -0,0 +1,461 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* private magic number for line objects */ | ||
5 | static const char o_type[] = "line"; | ||
6 | |||
7 | /* private struct for line object internal data */ | ||
8 | typedef struct _Evas_Object_Line Evas_Object_Line; | ||
9 | |||
10 | struct _Evas_Object_Line | ||
11 | { | ||
12 | DATA32 magic; | ||
13 | struct { | ||
14 | struct { | ||
15 | int x1, y1, x2, y2; | ||
16 | struct { | ||
17 | Evas_Coord w, h; | ||
18 | } object; | ||
19 | } cache; | ||
20 | Evas_Coord x1, y1, x2, y2; | ||
21 | } cur, prev; | ||
22 | |||
23 | void *engine_data; | ||
24 | |||
25 | char changed : 1; | ||
26 | }; | ||
27 | |||
28 | /* private methods for line objects */ | ||
29 | static void evas_object_line_init(Evas_Object *obj); | ||
30 | static void *evas_object_line_new(void); | ||
31 | static void evas_object_line_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y); | ||
32 | static void evas_object_line_free(Evas_Object *obj); | ||
33 | static void evas_object_line_render_pre(Evas_Object *obj); | ||
34 | static void evas_object_line_render_post(Evas_Object *obj); | ||
35 | |||
36 | static unsigned int evas_object_line_id_get(Evas_Object *obj); | ||
37 | static unsigned int evas_object_line_visual_id_get(Evas_Object *obj); | ||
38 | static void *evas_object_line_engine_data_get(Evas_Object *obj); | ||
39 | |||
40 | static int evas_object_line_is_opaque(Evas_Object *obj); | ||
41 | static int evas_object_line_was_opaque(Evas_Object *obj); | ||
42 | static int evas_object_line_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y); | ||
43 | static int evas_object_line_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y); | ||
44 | static void evas_object_line_coords_recalc(Evas_Object *obj); | ||
45 | |||
46 | static const Evas_Object_Func object_func = | ||
47 | { | ||
48 | /* methods (compulsory) */ | ||
49 | evas_object_line_free, | ||
50 | evas_object_line_render, | ||
51 | evas_object_line_render_pre, | ||
52 | evas_object_line_render_post, | ||
53 | evas_object_line_id_get, | ||
54 | evas_object_line_visual_id_get, | ||
55 | evas_object_line_engine_data_get, | ||
56 | /* these are optional. NULL = nothing */ | ||
57 | NULL, | ||
58 | NULL, | ||
59 | NULL, | ||
60 | NULL, | ||
61 | evas_object_line_is_opaque, | ||
62 | evas_object_line_was_opaque, | ||
63 | evas_object_line_is_inside, | ||
64 | evas_object_line_was_inside, | ||
65 | evas_object_line_coords_recalc, | ||
66 | NULL, | ||
67 | NULL, | ||
68 | NULL, | ||
69 | NULL | ||
70 | }; | ||
71 | |||
72 | /* the actual api call to add a rect */ | ||
73 | /* it has no other api calls as all properties are standard */ | ||
74 | |||
75 | EVAS_MEMPOOL(_mp_obj); | ||
76 | |||
77 | EAPI Evas_Object * | ||
78 | evas_object_line_add(Evas *e) | ||
79 | { | ||
80 | Evas_Object *obj; | ||
81 | |||
82 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
83 | return NULL; | ||
84 | MAGIC_CHECK_END(); | ||
85 | obj = evas_object_new(e); | ||
86 | evas_object_line_init(obj); | ||
87 | evas_object_inject(obj, e); | ||
88 | return obj; | ||
89 | } | ||
90 | |||
91 | EAPI void | ||
92 | evas_object_line_xy_set(Evas_Object *obj, Evas_Coord x1, Evas_Coord y1, Evas_Coord x2, Evas_Coord y2) | ||
93 | { | ||
94 | Evas_Object_Line *o; | ||
95 | Evas_Coord min_x, max_x, min_y, max_y; | ||
96 | int is, was = 0; | ||
97 | |||
98 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
99 | return; | ||
100 | MAGIC_CHECK_END(); | ||
101 | o = (Evas_Object_Line *)(obj->object_data); | ||
102 | MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE); | ||
103 | return; | ||
104 | MAGIC_CHECK_END(); | ||
105 | if ((x1 == o->cur.x1) && (y1 == o->cur.y1) && | ||
106 | (x2 == o->cur.x2) && (y2 == o->cur.y2)) return; | ||
107 | if (obj->layer->evas->events_frozen <= 0) | ||
108 | { | ||
109 | if (!evas_event_passes_through(obj) && | ||
110 | !evas_event_freezes_through(obj)) | ||
111 | was = evas_object_is_in_output_rect(obj, | ||
112 | obj->layer->evas->pointer.x, | ||
113 | obj->layer->evas->pointer.y, | ||
114 | 1, 1); | ||
115 | } | ||
116 | if (x1 < x2) | ||
117 | { | ||
118 | min_x = x1; | ||
119 | max_x = x2; | ||
120 | } | ||
121 | else | ||
122 | { | ||
123 | min_x = x2; | ||
124 | max_x = x1; | ||
125 | } | ||
126 | if (y1 < y2) | ||
127 | { | ||
128 | min_y = y1; | ||
129 | max_y = y2; | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | min_y = y2; | ||
134 | max_y = y1; | ||
135 | } | ||
136 | obj->cur.geometry.x = min_x; | ||
137 | obj->cur.geometry.y = min_y; | ||
138 | obj->cur.geometry.w = max_x - min_x + 2; | ||
139 | obj->cur.geometry.h = max_y - min_y + 2; | ||
140 | //// obj->cur.cache.geometry.validity = 0; | ||
141 | o->cur.x1 = x1 - min_x; | ||
142 | o->cur.y1 = y1 - min_y; | ||
143 | o->cur.x2 = x2 - min_x; | ||
144 | o->cur.y2 = y2 - min_y; | ||
145 | o->changed = 1; | ||
146 | evas_object_change(obj); | ||
147 | evas_object_coords_recalc(obj); | ||
148 | evas_object_clip_dirty(obj); | ||
149 | if (obj->layer->evas->events_frozen <= 0) | ||
150 | { | ||
151 | is = evas_object_is_in_output_rect(obj, | ||
152 | obj->layer->evas->pointer.x, | ||
153 | obj->layer->evas->pointer.y, 1, 1); | ||
154 | if (!evas_event_passes_through(obj) && | ||
155 | !evas_event_freezes_through(obj)) | ||
156 | { | ||
157 | if ((is ^ was) && obj->cur.visible) | ||
158 | evas_event_feed_mouse_move(obj->layer->evas, | ||
159 | obj->layer->evas->pointer.x, | ||
160 | obj->layer->evas->pointer.y, | ||
161 | obj->layer->evas->last_timestamp, | ||
162 | NULL); | ||
163 | } | ||
164 | } | ||
165 | evas_object_inform_call_move(obj); | ||
166 | evas_object_inform_call_resize(obj); | ||
167 | } | ||
168 | |||
169 | EAPI void | ||
170 | evas_object_line_xy_get(const Evas_Object *obj, Evas_Coord *x1, Evas_Coord *y1, Evas_Coord *x2, Evas_Coord *y2) | ||
171 | { | ||
172 | Evas_Object_Line *o; | ||
173 | |||
174 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
175 | if (x1) *x1 = 0; | ||
176 | if (y1) *y1 = 0; | ||
177 | if (x2) *x2 = 0; | ||
178 | if (y2) *y2 = 0; | ||
179 | return; | ||
180 | MAGIC_CHECK_END(); | ||
181 | o = (Evas_Object_Line *)(obj->object_data); | ||
182 | MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE); | ||
183 | if (x1) *x1 = 0; | ||
184 | if (y1) *y1 = 0; | ||
185 | if (x2) *x2 = 0; | ||
186 | if (y2) *y2 = 0; | ||
187 | return; | ||
188 | MAGIC_CHECK_END(); | ||
189 | if (x1) *x1 = obj->cur.geometry.x + o->cur.x1; | ||
190 | if (y1) *y1 = obj->cur.geometry.y + o->cur.y1; | ||
191 | if (x2) *x2 = obj->cur.geometry.x + o->cur.x2; | ||
192 | if (y2) *y2 = obj->cur.geometry.y + o->cur.y2; | ||
193 | } | ||
194 | |||
195 | /* all nice and private */ | ||
196 | static void | ||
197 | evas_object_line_init(Evas_Object *obj) | ||
198 | { | ||
199 | /* alloc image ob, setup methods and default values */ | ||
200 | obj->object_data = evas_object_line_new(); | ||
201 | /* set up default settings for this kind of object */ | ||
202 | obj->cur.color.r = 255; | ||
203 | obj->cur.color.g = 255; | ||
204 | obj->cur.color.b = 255; | ||
205 | obj->cur.color.a = 255; | ||
206 | obj->cur.geometry.x = 0; | ||
207 | obj->cur.geometry.y = 0; | ||
208 | obj->cur.geometry.w = 0; | ||
209 | obj->cur.geometry.h = 0; | ||
210 | obj->cur.layer = 0; | ||
211 | obj->cur.anti_alias = 1; | ||
212 | obj->cur.render_op = EVAS_RENDER_BLEND; | ||
213 | /* set up object-specific settings */ | ||
214 | obj->prev = obj->cur; | ||
215 | /* set up methods (compulsory) */ | ||
216 | obj->func = &object_func; | ||
217 | obj->type = o_type; | ||
218 | } | ||
219 | |||
220 | static void * | ||
221 | evas_object_line_new(void) | ||
222 | { | ||
223 | Evas_Object_Line *o; | ||
224 | |||
225 | /* alloc obj private data */ | ||
226 | EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_line", Evas_Object_Line, 16, NULL); | ||
227 | o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Line); | ||
228 | if (!o) return NULL; | ||
229 | EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Line); | ||
230 | o->magic = MAGIC_OBJ_LINE; | ||
231 | o->cur.x1 = 0; | ||
232 | o->cur.y1 = 0; | ||
233 | o->cur.x2 = 31; | ||
234 | o->cur.y2 = 31; | ||
235 | o->prev = o->cur; | ||
236 | return o; | ||
237 | } | ||
238 | |||
239 | static void | ||
240 | evas_object_line_free(Evas_Object *obj) | ||
241 | { | ||
242 | Evas_Object_Line *o; | ||
243 | |||
244 | /* frees private object data. very simple here */ | ||
245 | o = (Evas_Object_Line *)(obj->object_data); | ||
246 | MAGIC_CHECK(o, Evas_Object_Line, MAGIC_OBJ_LINE); | ||
247 | return; | ||
248 | MAGIC_CHECK_END(); | ||
249 | /* free obj */ | ||
250 | o->magic = 0; | ||
251 | EVAS_MEMPOOL_FREE(_mp_obj, o); | ||
252 | } | ||
253 | |||
254 | static void | ||
255 | evas_object_line_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y) | ||
256 | { | ||
257 | Evas_Object_Line *o; | ||
258 | |||
259 | /* render object to surface with context, and offxet by x,y */ | ||
260 | o = (Evas_Object_Line *)(obj->object_data); | ||
261 | obj->layer->evas->engine.func->context_color_set(output, | ||
262 | context, | ||
263 | obj->cur.cache.clip.r, | ||
264 | obj->cur.cache.clip.g, | ||
265 | obj->cur.cache.clip.b, | ||
266 | obj->cur.cache.clip.a); | ||
267 | obj->layer->evas->engine.func->context_multiplier_unset(output, | ||
268 | context); | ||
269 | obj->layer->evas->engine.func->context_anti_alias_set(output, context, | ||
270 | obj->cur.anti_alias); | ||
271 | obj->layer->evas->engine.func->context_render_op_set(output, context, | ||
272 | obj->cur.render_op); | ||
273 | obj->layer->evas->engine.func->line_draw(output, | ||
274 | context, | ||
275 | surface, | ||
276 | o->cur.cache.x1 + x, | ||
277 | o->cur.cache.y1 + y, | ||
278 | o->cur.cache.x2 + x, | ||
279 | o->cur.cache.y2 + y); | ||
280 | } | ||
281 | |||
282 | static void | ||
283 | evas_object_line_render_pre(Evas_Object *obj) | ||
284 | { | ||
285 | Evas_Object_Line *o; | ||
286 | int is_v, was_v; | ||
287 | |||
288 | /* dont pre-render the obj twice! */ | ||
289 | if (obj->pre_render_done) return; | ||
290 | obj->pre_render_done = 1; | ||
291 | /* pre-render phase. this does anything an object needs to do just before */ | ||
292 | /* rendering. this could mean loading the image data, retrieving it from */ | ||
293 | /* elsewhere, decoding video etc. */ | ||
294 | /* then when this is done the object needs to figure if it changed and */ | ||
295 | /* if so what and where and add the appropriate redraw lines */ | ||
296 | o = (Evas_Object_Line *)(obj->object_data); | ||
297 | /* if someone is clipping this obj - go calculate the clipper */ | ||
298 | if (obj->cur.clipper) | ||
299 | { | ||
300 | if (obj->cur.cache.clip.dirty) | ||
301 | evas_object_clip_recalc(obj->cur.clipper); | ||
302 | obj->cur.clipper->func->render_pre(obj->cur.clipper); | ||
303 | } | ||
304 | /* now figure what changed and add draw rects */ | ||
305 | /* if it just became visible or invisible */ | ||
306 | is_v = evas_object_is_visible(obj); | ||
307 | was_v = evas_object_was_visible(obj); | ||
308 | if (is_v != was_v) | ||
309 | { | ||
310 | evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v); | ||
311 | goto done; | ||
312 | } | ||
313 | if ((obj->cur.map != obj->prev.map) || | ||
314 | (obj->cur.usemap != obj->prev.usemap)) | ||
315 | { | ||
316 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
317 | goto done; | ||
318 | } | ||
319 | /* it's not visible - we accounted for it appearing or not so just abort */ | ||
320 | if (!is_v) goto done; | ||
321 | /* clipper changed this is in addition to anything else for obj */ | ||
322 | evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj); | ||
323 | /* if we restacked (layer or just within a layer) */ | ||
324 | if (obj->restack) | ||
325 | { | ||
326 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
327 | goto done; | ||
328 | } | ||
329 | /* if it changed anti_alias */ | ||
330 | if (obj->cur.anti_alias != obj->prev.anti_alias) | ||
331 | { | ||
332 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
333 | goto done; | ||
334 | } | ||
335 | /* if it changed render op */ | ||
336 | if (obj->cur.render_op != obj->prev.render_op) | ||
337 | { | ||
338 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
339 | goto done; | ||
340 | } | ||
341 | /* if it changed color */ | ||
342 | if ((obj->cur.color.r != obj->prev.color.r) || | ||
343 | (obj->cur.color.g != obj->prev.color.g) || | ||
344 | (obj->cur.color.b != obj->prev.color.b) || | ||
345 | (obj->cur.color.a != obj->prev.color.a)) | ||
346 | { | ||
347 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
348 | goto done; | ||
349 | } | ||
350 | /* if it changed geometry - and obviously not visibility or color */ | ||
351 | /* calculate differences since we have a constant color fill */ | ||
352 | /* we really only need to update the differences */ | ||
353 | if ((obj->cur.geometry.x != obj->prev.geometry.x) || | ||
354 | (obj->cur.geometry.y != obj->prev.geometry.y) || | ||
355 | (obj->cur.geometry.w != obj->prev.geometry.w) || | ||
356 | (obj->cur.geometry.h != obj->prev.geometry.h) || | ||
357 | ((o->changed) && | ||
358 | ((o->cur.x1 != o->prev.x1) || | ||
359 | (o->cur.y1 != o->prev.y1) || | ||
360 | (o->cur.x2 != o->prev.x2) || | ||
361 | (o->cur.y2 != o->prev.y2))) | ||
362 | ) | ||
363 | { | ||
364 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
365 | goto done; | ||
366 | } | ||
367 | done: | ||
368 | evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v); | ||
369 | } | ||
370 | |||
371 | static void | ||
372 | evas_object_line_render_post(Evas_Object *obj) | ||
373 | { | ||
374 | Evas_Object_Line *o; | ||
375 | |||
376 | /* this moves the current data to the previous state parts of the object */ | ||
377 | /* in whatever way is safest for the object. also if we don't need object */ | ||
378 | /* data anymore we can free it if the object deems this is a good idea */ | ||
379 | o = (Evas_Object_Line *)(obj->object_data); | ||
380 | /* remove those pesky changes */ | ||
381 | evas_object_clip_changes_clean(obj); | ||
382 | /* move cur to prev safely for object data */ | ||
383 | obj->prev = obj->cur; | ||
384 | o->prev = o->cur; | ||
385 | o->changed = 0; | ||
386 | } | ||
387 | |||
388 | static unsigned int evas_object_line_id_get(Evas_Object *obj) | ||
389 | { | ||
390 | Evas_Object_Line *o; | ||
391 | |||
392 | o = (Evas_Object_Line *)(obj->object_data); | ||
393 | if (!o) return 0; | ||
394 | return MAGIC_OBJ_LINE; | ||
395 | } | ||
396 | |||
397 | static unsigned int evas_object_line_visual_id_get(Evas_Object *obj) | ||
398 | { | ||
399 | Evas_Object_Line *o; | ||
400 | |||
401 | o = (Evas_Object_Line *)(obj->object_data); | ||
402 | if (!o) return 0; | ||
403 | return MAGIC_OBJ_SHAPE; | ||
404 | } | ||
405 | |||
406 | static void *evas_object_line_engine_data_get(Evas_Object *obj) | ||
407 | { | ||
408 | Evas_Object_Line *o; | ||
409 | |||
410 | o = (Evas_Object_Line *)(obj->object_data); | ||
411 | if (!o) return NULL; | ||
412 | return o->engine_data; | ||
413 | } | ||
414 | |||
415 | static int | ||
416 | evas_object_line_is_opaque(Evas_Object *obj __UNUSED__) | ||
417 | { | ||
418 | /* this returns 1 if the internal object data implies that the object is */ | ||
419 | /* currently fully opaque over the entire line it occupies */ | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int | ||
424 | evas_object_line_was_opaque(Evas_Object *obj __UNUSED__) | ||
425 | { | ||
426 | /* this returns 1 if the internal object data implies that the object was */ | ||
427 | /* previously fully opaque over the entire line it occupies */ | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static int | ||
432 | evas_object_line_is_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__) | ||
433 | { | ||
434 | /* this returns 1 if the canvas co-ordinates are inside the object based */ | ||
435 | /* on object private data. not much use for rects, but for polys, images */ | ||
436 | /* and other complex objects it might be */ | ||
437 | return 1; | ||
438 | } | ||
439 | |||
440 | static int | ||
441 | evas_object_line_was_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__) | ||
442 | { | ||
443 | /* this returns 1 if the canvas co-ordinates were inside the object based */ | ||
444 | /* on object private data. not much use for rects, but for polys, images */ | ||
445 | /* and other complex objects it might be */ | ||
446 | return 1; | ||
447 | } | ||
448 | |||
449 | static void | ||
450 | evas_object_line_coords_recalc(Evas_Object *obj) | ||
451 | { | ||
452 | Evas_Object_Line *o; | ||
453 | |||
454 | o = (Evas_Object_Line *)(obj->object_data); | ||
455 | o->cur.cache.x1 = obj->cur.geometry.x + o->cur.x1; | ||
456 | o->cur.cache.y1 = obj->cur.geometry.y + o->cur.y1; | ||
457 | o->cur.cache.x2 = obj->cur.geometry.x + o->cur.x2; | ||
458 | o->cur.cache.y2 = obj->cur.geometry.y + o->cur.y2; | ||
459 | o->cur.cache.object.w = obj->cur.geometry.w; | ||
460 | o->cur.cache.object.h = obj->cur.geometry.h; | ||
461 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_main.c b/libraries/evas/src/lib/canvas/evas_object_main.c new file mode 100644 index 0000000..3eaded9 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_main.c | |||
@@ -0,0 +1,1319 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | EVAS_MEMPOOL(_mp_obj); | ||
5 | EVAS_MEMPOOL(_mp_sh); | ||
6 | |||
7 | static Eina_Inlist * | ||
8 | get_layer_objects(Evas_Layer *l) | ||
9 | { | ||
10 | if ((!l) || (!l->objects)) return NULL; | ||
11 | return (EINA_INLIST_GET(l->objects)); | ||
12 | } | ||
13 | |||
14 | /* evas internal stuff */ | ||
15 | Evas_Object * | ||
16 | evas_object_new(Evas *e __UNUSED__) | ||
17 | { | ||
18 | Evas_Object *obj; | ||
19 | |||
20 | EVAS_MEMPOOL_INIT(_mp_obj, "evas_object", Evas_Object, 512, NULL); | ||
21 | obj = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object); | ||
22 | if (!obj) return NULL; | ||
23 | EVAS_MEMPOOL_PREP(_mp_obj, obj, Evas_Object); | ||
24 | |||
25 | obj->magic = MAGIC_OBJ; | ||
26 | obj->cur.scale = 1.0; | ||
27 | obj->prev.scale = 1.0; | ||
28 | |||
29 | return obj; | ||
30 | } | ||
31 | |||
32 | void | ||
33 | evas_object_free(Evas_Object *obj, int clean_layer) | ||
34 | { | ||
35 | int was_smart_child = 0; | ||
36 | |||
37 | #if 0 // filtering disabled | ||
38 | evas_filter_free(obj); | ||
39 | #endif | ||
40 | if (!strcmp(obj->type, "image")) evas_object_image_video_surface_set(obj, NULL); | ||
41 | evas_object_map_set(obj, NULL); | ||
42 | evas_object_grabs_cleanup(obj); | ||
43 | evas_object_intercept_cleanup(obj); | ||
44 | if (obj->smart.parent) was_smart_child = 1; | ||
45 | evas_object_smart_cleanup(obj); | ||
46 | obj->func->free(obj); | ||
47 | if (!was_smart_child) evas_object_release(obj, clean_layer); | ||
48 | if (obj->clip.clipees) | ||
49 | eina_list_free(obj->clip.clipees); | ||
50 | evas_object_clip_changes_clean(obj); | ||
51 | evas_object_event_callback_all_del(obj); | ||
52 | evas_object_event_callback_cleanup(obj); | ||
53 | while (obj->data.elements) | ||
54 | { | ||
55 | Evas_Data_Node *node; | ||
56 | |||
57 | node = obj->data.elements->data; | ||
58 | obj->data.elements = eina_list_remove(obj->data.elements, node); | ||
59 | free(node); | ||
60 | } | ||
61 | obj->magic = 0; | ||
62 | if (obj->size_hints) | ||
63 | { | ||
64 | EVAS_MEMPOOL_FREE(_mp_sh, obj->size_hints); | ||
65 | } | ||
66 | EVAS_MEMPOOL_FREE(_mp_obj, obj); | ||
67 | } | ||
68 | |||
69 | void | ||
70 | evas_object_change(Evas_Object *obj) | ||
71 | { | ||
72 | Eina_List *l; | ||
73 | Evas_Object *obj2; | ||
74 | Eina_Bool movch = 0; | ||
75 | |||
76 | if (obj->layer->evas->nochange) | ||
77 | { | ||
78 | // printf("nochange %p\n", obj); | ||
79 | return; | ||
80 | } | ||
81 | // else | ||
82 | // printf("ch %p\n", obj); | ||
83 | obj->layer->evas->changed = 1; | ||
84 | if (obj->changed_move) | ||
85 | { | ||
86 | movch = 1; | ||
87 | obj->changed_move = 0; | ||
88 | if (!obj->changed_nomove) obj->changed_move_only = 1; | ||
89 | if (obj->changed) return; | ||
90 | } | ||
91 | else | ||
92 | { | ||
93 | obj->changed_move_only = 0; | ||
94 | obj->changed_nomove = 1; | ||
95 | if (obj->changed) return; | ||
96 | } | ||
97 | // obj->changed = 1; | ||
98 | evas_render_object_recalc(obj); | ||
99 | /* set changed flag on all objects this one clips too */ | ||
100 | if (!((movch) && (obj->is_static_clip))) | ||
101 | { | ||
102 | EINA_LIST_FOREACH(obj->clip.clipees, l, obj2) evas_object_change(obj2); | ||
103 | } | ||
104 | EINA_LIST_FOREACH(obj->proxy.proxies, l, obj2) | ||
105 | { | ||
106 | evas_object_change(obj2); | ||
107 | } | ||
108 | if (obj->smart.parent) evas_object_change(obj->smart.parent); | ||
109 | } | ||
110 | |||
111 | void | ||
112 | evas_object_render_pre_visible_change(Eina_Array *rects, Evas_Object *obj, int is_v, int was_v) | ||
113 | { | ||
114 | if (obj->smart.smart) return ; | ||
115 | if (is_v == was_v) return ; | ||
116 | if (is_v) | ||
117 | { | ||
118 | evas_add_rect(rects, | ||
119 | obj->cur.cache.clip.x, | ||
120 | obj->cur.cache.clip.y, | ||
121 | obj->cur.cache.clip.w, | ||
122 | obj->cur.cache.clip.h); | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | evas_add_rect(rects, | ||
127 | obj->prev.cache.clip.x, | ||
128 | obj->prev.cache.clip.y, | ||
129 | obj->prev.cache.clip.w, | ||
130 | obj->prev.cache.clip.h); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | void | ||
135 | evas_object_render_pre_clipper_change(Eina_Array *rects, Evas_Object *obj) | ||
136 | { | ||
137 | if (obj->smart.smart) return ; | ||
138 | if (obj->cur.clipper == obj->prev.clipper) return ; | ||
139 | if ((obj->cur.clipper) && (obj->prev.clipper)) | ||
140 | { | ||
141 | /* get difference rects between clippers */ | ||
142 | evas_rects_return_difference_rects(rects, | ||
143 | obj->cur.clipper->cur.cache.clip.x, | ||
144 | obj->cur.clipper->cur.cache.clip.y, | ||
145 | obj->cur.clipper->cur.cache.clip.w, | ||
146 | obj->cur.clipper->cur.cache.clip.h, | ||
147 | obj->prev.clipper->prev.cache.clip.x, | ||
148 | obj->prev.clipper->prev.cache.clip.y, | ||
149 | obj->prev.clipper->prev.cache.clip.w, | ||
150 | obj->prev.clipper->prev.cache.clip.h); | ||
151 | } | ||
152 | else if (obj->cur.clipper) | ||
153 | { | ||
154 | evas_rects_return_difference_rects(rects, | ||
155 | obj->cur.geometry.x, | ||
156 | obj->cur.geometry.y, | ||
157 | obj->cur.geometry.w, | ||
158 | obj->cur.geometry.h, | ||
159 | //// rl = evas_rects_return_difference_rects(obj->cur.cache.geometry.x, | ||
160 | //// obj->cur.cache.geometry.y, | ||
161 | //// obj->cur.cache.geometry.w, | ||
162 | //// obj->cur.cache.geometry.h, | ||
163 | obj->cur.clipper->cur.cache.clip.x, | ||
164 | obj->cur.clipper->cur.cache.clip.y, | ||
165 | obj->cur.clipper->cur.cache.clip.w, | ||
166 | obj->cur.clipper->cur.cache.clip.h); | ||
167 | } | ||
168 | else if (obj->prev.clipper) | ||
169 | { | ||
170 | evas_rects_return_difference_rects(rects, | ||
171 | obj->prev.geometry.x, | ||
172 | obj->prev.geometry.y, | ||
173 | obj->prev.geometry.w, | ||
174 | obj->prev.geometry.h, | ||
175 | //// rl = evas_rects_return_difference_rects(obj->prev.cache.geometry.x, | ||
176 | //// obj->prev.cache.geometry.y, | ||
177 | //// obj->prev.cache.geometry.w, | ||
178 | //// obj->prev.cache.geometry.h, | ||
179 | obj->prev.clipper->prev.cache.clip.x, | ||
180 | obj->prev.clipper->prev.cache.clip.y, | ||
181 | obj->prev.clipper->prev.cache.clip.w, | ||
182 | obj->prev.clipper->prev.cache.clip.h); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | void | ||
187 | evas_object_render_pre_prev_cur_add(Eina_Array *rects, Evas_Object *obj) | ||
188 | { | ||
189 | evas_add_rect(rects, | ||
190 | obj->cur.cache.clip.x, | ||
191 | obj->cur.cache.clip.y, | ||
192 | obj->cur.cache.clip.w, | ||
193 | obj->cur.cache.clip.h); | ||
194 | evas_add_rect(rects, | ||
195 | obj->prev.cache.clip.x, | ||
196 | obj->prev.cache.clip.y, | ||
197 | obj->prev.cache.clip.w, | ||
198 | obj->prev.cache.clip.h); | ||
199 | /* | ||
200 | evas_add_rect(rects, | ||
201 | obj->cur.geometry.x, | ||
202 | obj->cur.geometry.y, | ||
203 | obj->cur.geometry.w, | ||
204 | obj->cur.geometry.h); | ||
205 | //// obj->cur.cache.geometry.x, | ||
206 | //// obj->cur.cache.geometry.y, | ||
207 | //// obj->cur.cache.geometry.w, | ||
208 | //// obj->cur.cache.geometry.h); | ||
209 | evas_add_rect(rects, | ||
210 | obj->prev.geometry.x, | ||
211 | obj->prev.geometry.y, | ||
212 | obj->prev.geometry.w, | ||
213 | obj->prev.geometry.h); | ||
214 | //// obj->prev.cache.geometry.x, | ||
215 | //// obj->prev.cache.geometry.y, | ||
216 | //// obj->prev.cache.geometry.w, | ||
217 | //// obj->prev.cache.geometry.h); | ||
218 | */ | ||
219 | } | ||
220 | |||
221 | void | ||
222 | evas_object_clip_changes_clean(Evas_Object *obj) | ||
223 | { | ||
224 | Eina_Rectangle *r; | ||
225 | |||
226 | EINA_LIST_FREE(obj->clip.changes, r) eina_rectangle_free(r); | ||
227 | } | ||
228 | |||
229 | void | ||
230 | evas_object_render_pre_effect_updates(Eina_Array *rects, Evas_Object *obj, int is_v, int was_v) | ||
231 | { | ||
232 | Eina_Rectangle *r; | ||
233 | Evas_Object *clipper; | ||
234 | Eina_List *l; | ||
235 | unsigned int i; | ||
236 | Eina_Array_Iterator it; | ||
237 | int x, y, w, h; | ||
238 | |||
239 | if (obj->smart.smart) goto end; | ||
240 | /* FIXME: was_v isn't used... why? */ | ||
241 | was_v = 0; | ||
242 | if (!obj->clip.clipees) | ||
243 | { | ||
244 | EINA_ARRAY_ITER_NEXT(rects, i, r, it) | ||
245 | { | ||
246 | /* get updates and clip to current clip */ | ||
247 | x = r->x; | ||
248 | y = r->y; | ||
249 | w = r->w; | ||
250 | h = r->h; | ||
251 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
252 | obj->cur.cache.clip.x, | ||
253 | obj->cur.cache.clip.y, | ||
254 | obj->cur.cache.clip.w, | ||
255 | obj->cur.cache.clip.h); | ||
256 | if ((w > 0) && (h > 0)) | ||
257 | obj->layer->evas->engine.func->output_redraws_rect_add(obj->layer->evas->engine.data.output, | ||
258 | x, y, w, h); | ||
259 | /* get updates and clip to previous clip */ | ||
260 | x = r->x; | ||
261 | y = r->y; | ||
262 | w = r->w; | ||
263 | h = r->h; | ||
264 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
265 | obj->prev.cache.clip.x, | ||
266 | obj->prev.cache.clip.y, | ||
267 | obj->prev.cache.clip.w, | ||
268 | obj->prev.cache.clip.h); | ||
269 | if ((w > 0) && (h > 0)) | ||
270 | obj->layer->evas->engine.func->output_redraws_rect_add(obj->layer->evas->engine.data.output, | ||
271 | x, y, w, h); | ||
272 | } | ||
273 | /* if the object is actually visible, take any parent clip changes */ | ||
274 | if (is_v) | ||
275 | { | ||
276 | clipper = obj->cur.clipper; | ||
277 | while (clipper) | ||
278 | { | ||
279 | EINA_LIST_FOREACH(clipper->clip.changes, l, r) | ||
280 | { | ||
281 | /* get updates and clip to current clip */ | ||
282 | x = r->x; y = r->y; w = r->w; h = r->h; | ||
283 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
284 | obj->cur.cache.clip.x, | ||
285 | obj->cur.cache.clip.y, | ||
286 | obj->cur.cache.clip.w, | ||
287 | obj->cur.cache.clip.h); | ||
288 | if ((w > 0) && (h > 0)) | ||
289 | obj->layer->evas->engine.func->output_redraws_rect_add(obj->layer->evas->engine.data.output, | ||
290 | x, y, w, h); | ||
291 | /* get updates and clip to previous clip */ | ||
292 | x = r->x; y = r->y; w = r->w; h = r->h; | ||
293 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
294 | obj->prev.cache.clip.x, | ||
295 | obj->prev.cache.clip.y, | ||
296 | obj->prev.cache.clip.w, | ||
297 | obj->prev.cache.clip.h); | ||
298 | if ((w > 0) && (h > 0)) | ||
299 | obj->layer->evas->engine.func->output_redraws_rect_add(obj->layer->evas->engine.data.output, | ||
300 | x, y, w, h); | ||
301 | } | ||
302 | clipper = clipper->cur.clipper; | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | evas_object_clip_changes_clean(obj); | ||
309 | EINA_ARRAY_ITER_NEXT(rects, i, r, it) | ||
310 | obj->clip.changes = eina_list_append(obj->clip.changes, r); | ||
311 | eina_array_clean(rects); | ||
312 | } | ||
313 | |||
314 | end: | ||
315 | EINA_ARRAY_ITER_NEXT(rects, i, r, it) | ||
316 | eina_rectangle_free(r); | ||
317 | eina_array_clean(rects); | ||
318 | } | ||
319 | |||
320 | int | ||
321 | evas_object_was_in_output_rect(Evas_Object *obj, int x, int y, int w, int h) | ||
322 | { | ||
323 | if (obj->smart.smart) return 0; | ||
324 | /* assumes coords have been recalced */ | ||
325 | if ((RECTS_INTERSECT(x, y, w, h, | ||
326 | obj->prev.cache.clip.x, | ||
327 | obj->prev.cache.clip.y, | ||
328 | obj->prev.cache.clip.w, | ||
329 | obj->prev.cache.clip.h))) | ||
330 | return 1; | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | int | ||
335 | evas_object_was_opaque(Evas_Object *obj) | ||
336 | { | ||
337 | if (obj->smart.smart) return 0; | ||
338 | if (obj->prev.cache.clip.a == 255) | ||
339 | { | ||
340 | if (obj->func->was_opaque) | ||
341 | return obj->func->was_opaque(obj); | ||
342 | return 1; | ||
343 | } | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | int | ||
348 | evas_object_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
349 | { | ||
350 | if (obj->smart.smart) return 0; | ||
351 | if (obj->func->is_inside) | ||
352 | return obj->func->is_inside(obj, x, y); | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | int | ||
357 | evas_object_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
358 | { | ||
359 | if (obj->smart.smart) return 0; | ||
360 | if (obj->func->was_inside) | ||
361 | return obj->func->was_inside(obj, x, y); | ||
362 | return 0; | ||
363 | } | ||
364 | /* routines apps will call */ | ||
365 | |||
366 | EAPI void | ||
367 | evas_object_ref(Evas_Object *obj) | ||
368 | { | ||
369 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
370 | return; | ||
371 | MAGIC_CHECK_END(); | ||
372 | obj->ref++; | ||
373 | if (obj->ref == 0) obj->ref--; | ||
374 | } | ||
375 | |||
376 | EAPI void | ||
377 | evas_object_unref(Evas_Object *obj) | ||
378 | { | ||
379 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
380 | return; | ||
381 | MAGIC_CHECK_END(); | ||
382 | if (obj->ref == 0) return; | ||
383 | obj->ref--; | ||
384 | if ((obj->del_ref) && (obj->ref == 0)) evas_object_del(obj); | ||
385 | } | ||
386 | |||
387 | EAPI void | ||
388 | evas_object_del(Evas_Object *obj) | ||
389 | { | ||
390 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
391 | return; | ||
392 | MAGIC_CHECK_END(); | ||
393 | |||
394 | if (obj->delete_me) return; | ||
395 | |||
396 | if (obj->ref > 0) | ||
397 | { | ||
398 | obj->del_ref = 1; | ||
399 | return; | ||
400 | } | ||
401 | #ifdef EVAS_FRAME_QUEUING | ||
402 | evas_common_frameq_flush(); | ||
403 | #endif | ||
404 | |||
405 | evas_object_hide(obj); | ||
406 | if (obj->focused) | ||
407 | { | ||
408 | obj->focused = 0; | ||
409 | obj->layer->evas->focused = NULL; | ||
410 | _evas_object_event_new(); | ||
411 | evas_object_event_callback_call(obj, EVAS_CALLBACK_FOCUS_OUT, NULL); | ||
412 | _evas_post_event_callback_call(obj->layer->evas); | ||
413 | } | ||
414 | _evas_object_event_new(); | ||
415 | evas_object_event_callback_call(obj, EVAS_CALLBACK_DEL, NULL); | ||
416 | _evas_post_event_callback_call(obj->layer->evas); | ||
417 | if (obj->mouse_grabbed > 0) | ||
418 | obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed; | ||
419 | if ((obj->mouse_in) || (obj->mouse_grabbed > 0)) | ||
420 | obj->layer->evas->pointer.object.in = eina_list_remove(obj->layer->evas->pointer.object.in, obj); | ||
421 | obj->mouse_grabbed = 0; | ||
422 | obj->mouse_in = 0; | ||
423 | if (obj->name) evas_object_name_set(obj, NULL); | ||
424 | if (!obj->layer) | ||
425 | { | ||
426 | evas_object_free(obj, 1); | ||
427 | return; | ||
428 | } | ||
429 | obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed; | ||
430 | obj->mouse_grabbed = 0; | ||
431 | obj->mouse_in = 0; | ||
432 | evas_object_grabs_cleanup(obj); | ||
433 | while (obj->clip.clipees) | ||
434 | evas_object_clip_unset(obj->clip.clipees->data); | ||
435 | while (obj->proxy.proxies) | ||
436 | evas_object_image_source_unset(obj->proxy.proxies->data); | ||
437 | if (obj->cur.clipper) evas_object_clip_unset(obj); | ||
438 | if (obj->smart.smart) evas_object_smart_del(obj); | ||
439 | evas_object_map_set(obj, NULL); | ||
440 | _evas_object_event_new(); | ||
441 | evas_object_event_callback_call(obj, EVAS_CALLBACK_FREE, NULL); | ||
442 | _evas_post_event_callback_call(obj->layer->evas); | ||
443 | evas_object_smart_cleanup(obj); | ||
444 | obj->delete_me = 1; | ||
445 | evas_object_change(obj); | ||
446 | } | ||
447 | |||
448 | EAPI void | ||
449 | evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
450 | { | ||
451 | int is, was = 0, pass = 0, freeze = 0; | ||
452 | |||
453 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
454 | return; | ||
455 | MAGIC_CHECK_END(); | ||
456 | if (obj->delete_me) return; | ||
457 | if (evas_object_intercept_call_move(obj, x, y)) return; | ||
458 | if (obj->doing.in_move > 0) | ||
459 | { | ||
460 | WRN("evas_object_move() called on object %p when in the middle of moving the same object", obj); | ||
461 | return; | ||
462 | } | ||
463 | if ((obj->cur.geometry.x == x) && (obj->cur.geometry.y == y)) return; | ||
464 | if (obj->layer->evas->events_frozen <= 0) | ||
465 | { | ||
466 | pass = evas_event_passes_through(obj); | ||
467 | freeze = evas_event_freezes_through(obj); | ||
468 | if ((!pass) && (!freeze)) | ||
469 | was = evas_object_is_in_output_rect(obj, | ||
470 | obj->layer->evas->pointer.x, | ||
471 | obj->layer->evas->pointer.y, 1, 1); | ||
472 | } | ||
473 | obj->doing.in_move++; | ||
474 | if (obj->smart.smart) | ||
475 | { | ||
476 | if (obj->smart.smart->smart_class->move) | ||
477 | obj->smart.smart->smart_class->move(obj, x, y); | ||
478 | } | ||
479 | obj->cur.geometry.x = x; | ||
480 | obj->cur.geometry.y = y; | ||
481 | //// obj->cur.cache.geometry.validity = 0; | ||
482 | obj->changed_move = 1; | ||
483 | evas_object_change(obj); | ||
484 | evas_object_clip_dirty(obj); | ||
485 | obj->doing.in_move--; | ||
486 | if (obj->layer->evas->events_frozen <= 0) | ||
487 | { | ||
488 | evas_object_recalc_clippees(obj); | ||
489 | if (!pass) | ||
490 | { | ||
491 | if (!obj->smart.smart) | ||
492 | { | ||
493 | is = evas_object_is_in_output_rect(obj, | ||
494 | obj->layer->evas->pointer.x, | ||
495 | obj->layer->evas->pointer.y, 1, 1); | ||
496 | if ((is ^ was) && obj->cur.visible) | ||
497 | evas_event_feed_mouse_move(obj->layer->evas, | ||
498 | obj->layer->evas->pointer.x, | ||
499 | obj->layer->evas->pointer.y, | ||
500 | obj->layer->evas->last_timestamp, | ||
501 | NULL); | ||
502 | } | ||
503 | } | ||
504 | } | ||
505 | evas_object_inform_call_move(obj); | ||
506 | } | ||
507 | |||
508 | EAPI void | ||
509 | evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) | ||
510 | { | ||
511 | int is, was = 0, pass = 0, freeze =0; | ||
512 | |||
513 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
514 | return; | ||
515 | MAGIC_CHECK_END(); | ||
516 | if (obj->delete_me) return; | ||
517 | if (w < 0) w = 0; if (h < 0) h = 0; | ||
518 | if (evas_object_intercept_call_resize(obj, w, h)) return; | ||
519 | if (obj->doing.in_resize > 0) | ||
520 | { | ||
521 | WRN("evas_object_resize() called on object %p when in the middle of resizing the same object", obj); | ||
522 | return; | ||
523 | } | ||
524 | if ((obj->cur.geometry.w == w) && (obj->cur.geometry.h == h)) return; | ||
525 | if (obj->layer->evas->events_frozen <= 0) | ||
526 | { | ||
527 | pass = evas_event_passes_through(obj); | ||
528 | freeze = evas_event_freezes_through(obj); | ||
529 | if ((!pass) && (!freeze)) | ||
530 | was = evas_object_is_in_output_rect(obj, | ||
531 | obj->layer->evas->pointer.x, | ||
532 | obj->layer->evas->pointer.y, 1, 1); | ||
533 | } | ||
534 | obj->doing.in_resize++; | ||
535 | if (obj->smart.smart) | ||
536 | { | ||
537 | if (obj->smart.smart->smart_class->resize) | ||
538 | obj->smart.smart->smart_class->resize(obj, w, h); | ||
539 | } | ||
540 | obj->cur.geometry.w = w; | ||
541 | obj->cur.geometry.h = h; | ||
542 | //// obj->cur.cache.geometry.validity = 0; | ||
543 | evas_object_change(obj); | ||
544 | evas_object_clip_dirty(obj); | ||
545 | obj->doing.in_resize--; | ||
546 | /* NB: evas_object_recalc_clippees was here previously ( < 08/07/2009) */ | ||
547 | if (obj->layer->evas->events_frozen <= 0) | ||
548 | { | ||
549 | /* NB: If this creates glitches on screen then move to above position */ | ||
550 | evas_object_recalc_clippees(obj); | ||
551 | |||
552 | // if (obj->func->coords_recalc) obj->func->coords_recalc(obj); | ||
553 | if (!pass) | ||
554 | { | ||
555 | if (!obj->smart.smart) | ||
556 | { | ||
557 | is = evas_object_is_in_output_rect(obj, | ||
558 | obj->layer->evas->pointer.x, | ||
559 | obj->layer->evas->pointer.y, 1, 1); | ||
560 | if ((is ^ was) && (obj->cur.visible)) | ||
561 | evas_event_feed_mouse_move(obj->layer->evas, | ||
562 | obj->layer->evas->pointer.x, | ||
563 | obj->layer->evas->pointer.y, | ||
564 | obj->layer->evas->last_timestamp, | ||
565 | NULL); | ||
566 | } | ||
567 | } | ||
568 | } | ||
569 | evas_object_inform_call_resize(obj); | ||
570 | } | ||
571 | |||
572 | EAPI void | ||
573 | evas_object_geometry_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) | ||
574 | { | ||
575 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
576 | if (x) *x = 0; if (y) *y = 0; if (w) *w = 0; if (h) *h = 0; | ||
577 | return; | ||
578 | MAGIC_CHECK_END(); | ||
579 | if (obj->delete_me) | ||
580 | { | ||
581 | if (x) *x = 0; if (y) *y = 0; if (w) *w = 0; if (h) *h = 0; | ||
582 | return; | ||
583 | } | ||
584 | if (x) *x = obj->cur.geometry.x; | ||
585 | if (y) *y = obj->cur.geometry.y; | ||
586 | if (w) *w = obj->cur.geometry.w; | ||
587 | if (h) *h = obj->cur.geometry.h; | ||
588 | } | ||
589 | |||
590 | static void | ||
591 | _evas_object_size_hint_alloc(Evas_Object *obj) | ||
592 | { | ||
593 | if (obj->size_hints) return; | ||
594 | |||
595 | EVAS_MEMPOOL_INIT(_mp_sh, "evas_size_hints", Evas_Size_Hints, 512, ); | ||
596 | obj->size_hints = EVAS_MEMPOOL_ALLOC(_mp_sh, Evas_Size_Hints); | ||
597 | if (!obj->size_hints) return; | ||
598 | EVAS_MEMPOOL_PREP(_mp_sh, obj->size_hints, Evas_Size_Hints); | ||
599 | obj->size_hints->max.w = -1; | ||
600 | obj->size_hints->max.h = -1; | ||
601 | obj->size_hints->align.x = 0.5; | ||
602 | obj->size_hints->align.y = 0.5; | ||
603 | } | ||
604 | |||
605 | EAPI void | ||
606 | evas_object_size_hint_min_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) | ||
607 | { | ||
608 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
609 | if (w) *w = 0; if (h) *h = 0; | ||
610 | return; | ||
611 | MAGIC_CHECK_END(); | ||
612 | if ((!obj->size_hints) || obj->delete_me) | ||
613 | { | ||
614 | if (w) *w = 0; if (h) *h = 0; | ||
615 | return; | ||
616 | } | ||
617 | if (w) *w = obj->size_hints->min.w; | ||
618 | if (h) *h = obj->size_hints->min.h; | ||
619 | } | ||
620 | |||
621 | EAPI void | ||
622 | evas_object_size_hint_min_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h) | ||
623 | { | ||
624 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
625 | return; | ||
626 | MAGIC_CHECK_END(); | ||
627 | if (obj->delete_me) | ||
628 | return; | ||
629 | _evas_object_size_hint_alloc(obj); | ||
630 | if ((obj->size_hints->min.w == w) && (obj->size_hints->min.h == h)) return; | ||
631 | obj->size_hints->min.w = w; | ||
632 | obj->size_hints->min.h = h; | ||
633 | |||
634 | evas_object_inform_call_changed_size_hints(obj); | ||
635 | } | ||
636 | |||
637 | EAPI void | ||
638 | evas_object_size_hint_max_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) | ||
639 | { | ||
640 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
641 | if (w) *w = -1; if (h) *h = -1; | ||
642 | return; | ||
643 | MAGIC_CHECK_END(); | ||
644 | if ((!obj->size_hints) || obj->delete_me) | ||
645 | { | ||
646 | if (w) *w = -1; if (h) *h = -1; | ||
647 | return; | ||
648 | } | ||
649 | if (w) *w = obj->size_hints->max.w; | ||
650 | if (h) *h = obj->size_hints->max.h; | ||
651 | } | ||
652 | |||
653 | EAPI void | ||
654 | evas_object_size_hint_max_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h) | ||
655 | { | ||
656 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
657 | return; | ||
658 | MAGIC_CHECK_END(); | ||
659 | if (obj->delete_me) | ||
660 | return; | ||
661 | _evas_object_size_hint_alloc(obj); | ||
662 | if ((obj->size_hints->max.w == w) && (obj->size_hints->max.h == h)) return; | ||
663 | obj->size_hints->max.w = w; | ||
664 | obj->size_hints->max.h = h; | ||
665 | |||
666 | evas_object_inform_call_changed_size_hints(obj); | ||
667 | } | ||
668 | |||
669 | EAPI void | ||
670 | evas_object_size_hint_request_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) | ||
671 | { | ||
672 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
673 | if (w) *w = 0; if (h) *h = 0; | ||
674 | return; | ||
675 | MAGIC_CHECK_END(); | ||
676 | if ((!obj->size_hints) || obj->delete_me) | ||
677 | { | ||
678 | if (w) *w = 0; if (h) *h = 0; | ||
679 | return; | ||
680 | } | ||
681 | if (w) *w = obj->size_hints->request.w; | ||
682 | if (h) *h = obj->size_hints->request.h; | ||
683 | } | ||
684 | |||
685 | EAPI void | ||
686 | evas_object_size_hint_request_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h) | ||
687 | { | ||
688 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
689 | return; | ||
690 | MAGIC_CHECK_END(); | ||
691 | if (obj->delete_me) | ||
692 | return; | ||
693 | _evas_object_size_hint_alloc(obj); | ||
694 | if ((obj->size_hints->request.w == w) && (obj->size_hints->request.h == h)) return; | ||
695 | obj->size_hints->request.w = w; | ||
696 | obj->size_hints->request.h = h; | ||
697 | |||
698 | evas_object_inform_call_changed_size_hints(obj); | ||
699 | } | ||
700 | |||
701 | EAPI void | ||
702 | evas_object_size_hint_aspect_get(const Evas_Object *obj, Evas_Aspect_Control *aspect, Evas_Coord *w, Evas_Coord *h) | ||
703 | { | ||
704 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
705 | if (aspect) *aspect = EVAS_ASPECT_CONTROL_NONE; | ||
706 | if (w) *w = 0; if (h) *h = 0; | ||
707 | return; | ||
708 | MAGIC_CHECK_END(); | ||
709 | if ((!obj->size_hints) || obj->delete_me) | ||
710 | { | ||
711 | if (aspect) *aspect = EVAS_ASPECT_CONTROL_NONE; | ||
712 | if (w) *w = 0; if (h) *h = 0; | ||
713 | return; | ||
714 | } | ||
715 | if (aspect) *aspect = obj->size_hints->aspect.mode; | ||
716 | if (w) *w = obj->size_hints->aspect.size.w; | ||
717 | if (h) *h = obj->size_hints->aspect.size.h; | ||
718 | } | ||
719 | |||
720 | EAPI void | ||
721 | evas_object_size_hint_aspect_set(Evas_Object *obj, Evas_Aspect_Control aspect, Evas_Coord w, Evas_Coord h) | ||
722 | { | ||
723 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
724 | return; | ||
725 | MAGIC_CHECK_END(); | ||
726 | if (obj->delete_me) | ||
727 | return; | ||
728 | _evas_object_size_hint_alloc(obj); | ||
729 | if ((obj->size_hints->aspect.mode == aspect) && (obj->size_hints->aspect.size.w == w) && (obj->size_hints->aspect.size.h == h)) return; | ||
730 | obj->size_hints->aspect.mode = aspect; | ||
731 | obj->size_hints->aspect.size.w = w; | ||
732 | obj->size_hints->aspect.size.h = h; | ||
733 | |||
734 | evas_object_inform_call_changed_size_hints(obj); | ||
735 | } | ||
736 | |||
737 | EAPI void | ||
738 | evas_object_size_hint_align_get(const Evas_Object *obj, double *x, double *y) | ||
739 | { | ||
740 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
741 | if (x) *x = 0.5; if (y) *y = 0.5; | ||
742 | return; | ||
743 | MAGIC_CHECK_END(); | ||
744 | if ((!obj->size_hints) || obj->delete_me) | ||
745 | { | ||
746 | if (x) *x = 0.5; if (y) *y = 0.5; | ||
747 | return; | ||
748 | } | ||
749 | if (x) *x = obj->size_hints->align.x; | ||
750 | if (y) *y = obj->size_hints->align.y; | ||
751 | } | ||
752 | |||
753 | EAPI void | ||
754 | evas_object_size_hint_align_set(Evas_Object *obj, double x, double y) | ||
755 | { | ||
756 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
757 | return; | ||
758 | MAGIC_CHECK_END(); | ||
759 | if (obj->delete_me) | ||
760 | return; | ||
761 | _evas_object_size_hint_alloc(obj); | ||
762 | if ((obj->size_hints->align.x == x) && (obj->size_hints->align.y == y)) return; | ||
763 | obj->size_hints->align.x = x; | ||
764 | obj->size_hints->align.y = y; | ||
765 | |||
766 | evas_object_inform_call_changed_size_hints(obj); | ||
767 | } | ||
768 | |||
769 | EAPI void | ||
770 | evas_object_size_hint_weight_get(const Evas_Object *obj, double *x, double *y) | ||
771 | { | ||
772 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
773 | if (x) *x = 0.0; if (y) *y = 0.0; | ||
774 | return; | ||
775 | MAGIC_CHECK_END(); | ||
776 | if ((!obj->size_hints) || obj->delete_me) | ||
777 | { | ||
778 | if (x) *x = 0.0; if (y) *y = 0.0; | ||
779 | return; | ||
780 | } | ||
781 | if (x) *x = obj->size_hints->weight.x; | ||
782 | if (y) *y = obj->size_hints->weight.y; | ||
783 | } | ||
784 | |||
785 | EAPI void | ||
786 | evas_object_size_hint_weight_set(Evas_Object *obj, double x, double y) | ||
787 | { | ||
788 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
789 | return; | ||
790 | MAGIC_CHECK_END(); | ||
791 | if (obj->delete_me) | ||
792 | return; | ||
793 | _evas_object_size_hint_alloc(obj); | ||
794 | if ((obj->size_hints->weight.x == x) && (obj->size_hints->weight.y == y)) return; | ||
795 | obj->size_hints->weight.x = x; | ||
796 | obj->size_hints->weight.y = y; | ||
797 | |||
798 | evas_object_inform_call_changed_size_hints(obj); | ||
799 | } | ||
800 | |||
801 | EAPI void | ||
802 | evas_object_size_hint_padding_get(const Evas_Object *obj, Evas_Coord *l, Evas_Coord *r, Evas_Coord *t, Evas_Coord *b) | ||
803 | { | ||
804 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
805 | if (l) *l = 0; if (r) *r = 0; | ||
806 | if (t) *t = 0; if (b) *b = 0; | ||
807 | return; | ||
808 | MAGIC_CHECK_END(); | ||
809 | if ((!obj->size_hints) || obj->delete_me) | ||
810 | { | ||
811 | if (l) *l = 0; if (r) *r = 0; | ||
812 | if (t) *t = 0; if (b) *b = 0; | ||
813 | return; | ||
814 | } | ||
815 | if (l) *l = obj->size_hints->padding.l; | ||
816 | if (r) *r = obj->size_hints->padding.r; | ||
817 | if (t) *t = obj->size_hints->padding.t; | ||
818 | if (b) *b = obj->size_hints->padding.b; | ||
819 | } | ||
820 | |||
821 | EAPI void | ||
822 | evas_object_size_hint_padding_set(Evas_Object *obj, Evas_Coord l, Evas_Coord r, Evas_Coord t, Evas_Coord b) | ||
823 | { | ||
824 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
825 | return; | ||
826 | MAGIC_CHECK_END(); | ||
827 | if (obj->delete_me) | ||
828 | return; | ||
829 | _evas_object_size_hint_alloc(obj); | ||
830 | if ((obj->size_hints->padding.l == l) && (obj->size_hints->padding.r == r) && (obj->size_hints->padding.t == t) && (obj->size_hints->padding.b == b)) return; | ||
831 | obj->size_hints->padding.l = l; | ||
832 | obj->size_hints->padding.r = r; | ||
833 | obj->size_hints->padding.t = t; | ||
834 | obj->size_hints->padding.b = b; | ||
835 | |||
836 | evas_object_inform_call_changed_size_hints(obj); | ||
837 | } | ||
838 | |||
839 | EAPI void | ||
840 | evas_object_show(Evas_Object *obj) | ||
841 | { | ||
842 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
843 | return; | ||
844 | MAGIC_CHECK_END(); | ||
845 | if (obj->delete_me) return; | ||
846 | if (evas_object_intercept_call_show(obj)) return; | ||
847 | if (obj->smart.smart) | ||
848 | { | ||
849 | if (obj->smart.smart->smart_class->show) | ||
850 | obj->smart.smart->smart_class->show(obj); | ||
851 | } | ||
852 | if (obj->cur.visible) | ||
853 | { | ||
854 | return; | ||
855 | } | ||
856 | obj->cur.visible = 1; | ||
857 | evas_object_change(obj); | ||
858 | evas_object_clip_dirty(obj); | ||
859 | if (obj->layer->evas->events_frozen <= 0) | ||
860 | { | ||
861 | evas_object_clip_across_clippees_check(obj); | ||
862 | evas_object_recalc_clippees(obj); | ||
863 | if ((!evas_event_passes_through(obj)) && | ||
864 | (!evas_event_freezes_through(obj))) | ||
865 | { | ||
866 | if (!obj->smart.smart) | ||
867 | { | ||
868 | if (evas_object_is_in_output_rect(obj, | ||
869 | obj->layer->evas->pointer.x, | ||
870 | obj->layer->evas->pointer.y, 1, 1)) | ||
871 | evas_event_feed_mouse_move(obj->layer->evas, | ||
872 | obj->layer->evas->pointer.x, | ||
873 | obj->layer->evas->pointer.y, | ||
874 | obj->layer->evas->last_timestamp, | ||
875 | NULL); | ||
876 | } | ||
877 | } | ||
878 | } | ||
879 | evas_object_inform_call_show(obj); | ||
880 | } | ||
881 | |||
882 | EAPI void | ||
883 | evas_object_hide(Evas_Object *obj) | ||
884 | { | ||
885 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
886 | return; | ||
887 | MAGIC_CHECK_END(); | ||
888 | if (obj->delete_me) return; | ||
889 | if (evas_object_intercept_call_hide(obj)) return; | ||
890 | if (obj->smart.smart) | ||
891 | { | ||
892 | if (obj->smart.smart->smart_class->hide) | ||
893 | obj->smart.smart->smart_class->hide(obj); | ||
894 | } | ||
895 | if (!obj->cur.visible) | ||
896 | { | ||
897 | return; | ||
898 | } | ||
899 | obj->cur.visible = 0; | ||
900 | evas_object_change(obj); | ||
901 | evas_object_clip_dirty(obj); | ||
902 | if (obj->layer->evas->events_frozen <= 0) | ||
903 | { | ||
904 | evas_object_clip_across_clippees_check(obj); | ||
905 | evas_object_recalc_clippees(obj); | ||
906 | if ((!evas_event_passes_through(obj)) && | ||
907 | (!evas_event_freezes_through(obj))) | ||
908 | { | ||
909 | if ((!obj->smart.smart) || | ||
910 | ((obj->cur.map) && (obj->cur.map->count == 4) && (obj->cur.usemap))) | ||
911 | { | ||
912 | if (!obj->mouse_grabbed) | ||
913 | { | ||
914 | if (evas_object_is_in_output_rect(obj, | ||
915 | obj->layer->evas->pointer.x, | ||
916 | obj->layer->evas->pointer.y, 1, 1)) | ||
917 | evas_event_feed_mouse_move(obj->layer->evas, | ||
918 | obj->layer->evas->pointer.x, | ||
919 | obj->layer->evas->pointer.y, | ||
920 | obj->layer->evas->last_timestamp, | ||
921 | NULL); | ||
922 | } | ||
923 | /* this is at odds to handling events when an obj is moved out of the mouse | ||
924 | * ore resized out or clipped out. if mouse is grabbed - regardless of | ||
925 | * visibility, mouse move events should keep happening and mouse up. | ||
926 | * for better or worse it's at least consistent. | ||
927 | if (obj->delete_me) return; | ||
928 | if (obj->mouse_grabbed > 0) | ||
929 | obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed; | ||
930 | if ((obj->mouse_in) || (obj->mouse_grabbed > 0)) | ||
931 | obj->layer->evas->pointer.object.in = eina_list_remove(obj->layer->evas->pointer.object.in, obj); | ||
932 | obj->mouse_grabbed = 0; | ||
933 | if (obj->layer->evas->events_frozen > 0) | ||
934 | { | ||
935 | obj->mouse_in = 0; | ||
936 | return; | ||
937 | } | ||
938 | if (obj->mouse_in) | ||
939 | { | ||
940 | Evas_Event_Mouse_Out ev; | ||
941 | |||
942 | _evas_object_event_new(); | ||
943 | |||
944 | obj->mouse_in = 0; | ||
945 | ev.buttons = obj->layer->evas->pointer.button; | ||
946 | ev.output.x = obj->layer->evas->pointer.x; | ||
947 | ev.output.y = obj->layer->evas->pointer.y; | ||
948 | ev.canvas.x = obj->layer->evas->pointer.x; | ||
949 | ev.canvas.y = obj->layer->evas->pointer.y; | ||
950 | ev.data = NULL; | ||
951 | ev.modifiers = &(obj->layer->evas->modifiers); | ||
952 | ev.locks = &(obj->layer->evas->locks); | ||
953 | ev.timestamp = obj->layer->evas->last_timestamp; | ||
954 | ev.event_flags = EVAS_EVENT_FLAG_NONE; | ||
955 | evas_object_event_callback_call(obj, EVAS_CALLBACK_MOUSE_OUT, &ev); | ||
956 | _evas_post_event_callback_call(obj->layer->evas); | ||
957 | } | ||
958 | */ | ||
959 | } | ||
960 | } | ||
961 | } | ||
962 | else | ||
963 | { | ||
964 | /* | ||
965 | if (obj->mouse_grabbed > 0) | ||
966 | obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed; | ||
967 | if ((obj->mouse_in) || (obj->mouse_grabbed > 0)) | ||
968 | obj->layer->evas->pointer.object.in = eina_list_remove(obj->layer->evas->pointer.object.in, obj); | ||
969 | obj->mouse_grabbed = 0; | ||
970 | obj->mouse_in = 0; | ||
971 | */ | ||
972 | } | ||
973 | evas_object_inform_call_hide(obj); | ||
974 | } | ||
975 | |||
976 | EAPI Eina_Bool | ||
977 | evas_object_visible_get(const Evas_Object *obj) | ||
978 | { | ||
979 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
980 | return 0; | ||
981 | MAGIC_CHECK_END(); | ||
982 | if (obj->delete_me) return 0; | ||
983 | return obj->cur.visible; | ||
984 | } | ||
985 | |||
986 | EAPI void | ||
987 | evas_object_color_set(Evas_Object *obj, int r, int g, int b, int a) | ||
988 | { | ||
989 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
990 | return; | ||
991 | MAGIC_CHECK_END(); | ||
992 | if (obj->delete_me) return; | ||
993 | if (r > 255) r = 255; if (r < 0) r = 0; | ||
994 | if (g > 255) g = 255; if (g < 0) g = 0; | ||
995 | if (b > 255) b = 255; if (b < 0) b = 0; | ||
996 | if (a > 255) a = 255; if (a < 0) a = 0; | ||
997 | if (evas_object_intercept_call_color_set(obj, r, g, b, a)) return; | ||
998 | if (obj->smart.smart) | ||
999 | { | ||
1000 | if (obj->smart.smart->smart_class->color_set) | ||
1001 | obj->smart.smart->smart_class->color_set(obj, r, g, b, a); | ||
1002 | } | ||
1003 | if ((obj->cur.color.r == r) && | ||
1004 | (obj->cur.color.g == g) && | ||
1005 | (obj->cur.color.b == b) && | ||
1006 | (obj->cur.color.a == a)) return; | ||
1007 | obj->cur.color.r = r; | ||
1008 | obj->cur.color.g = g; | ||
1009 | obj->cur.color.b = b; | ||
1010 | evas_object_clip_dirty(obj); | ||
1011 | if ((obj->cur.color.a == 0) && (a == 0) && (obj->cur.render_op == EVAS_RENDER_BLEND)) return; | ||
1012 | obj->cur.color.a = a; | ||
1013 | evas_object_change(obj); | ||
1014 | } | ||
1015 | |||
1016 | EAPI void | ||
1017 | evas_object_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a) | ||
1018 | { | ||
1019 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1020 | if (r) *r = 0; if (g) *g = 0; if (b) *b = 0; if (a) *a = 0; | ||
1021 | return; | ||
1022 | MAGIC_CHECK_END(); | ||
1023 | if (obj->delete_me) | ||
1024 | { | ||
1025 | if (r) *r = 0; if (g) *g = 0; if (b) *b = 0; if (a) *a = 0; | ||
1026 | return; | ||
1027 | } | ||
1028 | if (r) *r = obj->cur.color.r; | ||
1029 | if (g) *g = obj->cur.color.g; | ||
1030 | if (b) *b = obj->cur.color.b; | ||
1031 | if (a) *a = obj->cur.color.a; | ||
1032 | } | ||
1033 | |||
1034 | EAPI void | ||
1035 | evas_object_anti_alias_set(Evas_Object *obj, Eina_Bool anti_alias) | ||
1036 | { | ||
1037 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1038 | return; | ||
1039 | MAGIC_CHECK_END(); | ||
1040 | if (obj->delete_me) return; | ||
1041 | anti_alias = !!anti_alias; | ||
1042 | if (obj->cur.anti_alias == anti_alias)return; | ||
1043 | obj->cur.anti_alias = anti_alias; | ||
1044 | evas_object_change(obj); | ||
1045 | } | ||
1046 | |||
1047 | EAPI Eina_Bool | ||
1048 | evas_object_anti_alias_get(const Evas_Object *obj) | ||
1049 | { | ||
1050 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1051 | return 0; | ||
1052 | MAGIC_CHECK_END(); | ||
1053 | if (obj->delete_me) return 0; | ||
1054 | return obj->cur.anti_alias; | ||
1055 | } | ||
1056 | |||
1057 | EAPI void | ||
1058 | evas_object_scale_set(Evas_Object *obj, double scale) | ||
1059 | { | ||
1060 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1061 | return; | ||
1062 | MAGIC_CHECK_END(); | ||
1063 | if (obj->delete_me) return; | ||
1064 | if (obj->cur.scale == scale) return; | ||
1065 | obj->cur.scale = scale; | ||
1066 | evas_object_change(obj); | ||
1067 | if (obj->func->scale_update) obj->func->scale_update(obj); | ||
1068 | } | ||
1069 | |||
1070 | EAPI double | ||
1071 | evas_object_scale_get(const Evas_Object *obj) | ||
1072 | { | ||
1073 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1074 | return 0; | ||
1075 | MAGIC_CHECK_END(); | ||
1076 | if (obj->delete_me) return 1.0; | ||
1077 | return obj->cur.scale; | ||
1078 | } | ||
1079 | |||
1080 | EAPI void | ||
1081 | evas_object_render_op_set(Evas_Object *obj, Evas_Render_Op render_op) | ||
1082 | { | ||
1083 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1084 | return; | ||
1085 | MAGIC_CHECK_END(); | ||
1086 | if (obj->delete_me) return; | ||
1087 | if ((Evas_Render_Op)obj->cur.render_op == render_op) | ||
1088 | return; | ||
1089 | obj->cur.render_op = render_op; | ||
1090 | evas_object_change(obj); | ||
1091 | } | ||
1092 | |||
1093 | EAPI Evas_Render_Op | ||
1094 | evas_object_render_op_get(const Evas_Object *obj) | ||
1095 | { | ||
1096 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1097 | return 0; | ||
1098 | MAGIC_CHECK_END(); | ||
1099 | if (obj->delete_me) return EVAS_RENDER_BLEND; | ||
1100 | return obj->cur.render_op; | ||
1101 | } | ||
1102 | |||
1103 | EAPI Evas * | ||
1104 | evas_object_evas_get(const Evas_Object *obj) | ||
1105 | { | ||
1106 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1107 | return NULL; | ||
1108 | MAGIC_CHECK_END(); | ||
1109 | if (obj->delete_me) return NULL; | ||
1110 | return obj->layer->evas; | ||
1111 | } | ||
1112 | |||
1113 | EAPI Evas_Object * | ||
1114 | evas_object_top_at_xy_get(const Evas *e, Evas_Coord x, Evas_Coord y, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects) | ||
1115 | { | ||
1116 | Evas_Layer *lay; | ||
1117 | int xx, yy; | ||
1118 | |||
1119 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1120 | return NULL; | ||
1121 | MAGIC_CHECK_END(); | ||
1122 | xx = x; | ||
1123 | yy = y; | ||
1124 | //// xx = evas_coord_world_x_to_screen(e, x); | ||
1125 | //// yy = evas_coord_world_y_to_screen(e, y); | ||
1126 | EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay) | ||
1127 | { | ||
1128 | Evas_Object *obj; | ||
1129 | |||
1130 | EINA_INLIST_REVERSE_FOREACH(get_layer_objects(lay), obj) | ||
1131 | { | ||
1132 | if (obj->delete_me) continue; | ||
1133 | if ((!include_pass_events_objects) && | ||
1134 | (evas_event_passes_through(obj))) continue; | ||
1135 | if ((!include_hidden_objects) && (!obj->cur.visible)) continue; | ||
1136 | evas_object_clip_recalc(obj); | ||
1137 | if ((evas_object_is_in_output_rect(obj, xx, yy, 1, 1)) && | ||
1138 | (!obj->clip.clipees)) | ||
1139 | return obj; | ||
1140 | } | ||
1141 | } | ||
1142 | return NULL; | ||
1143 | } | ||
1144 | |||
1145 | EAPI Evas_Object * | ||
1146 | evas_object_top_at_pointer_get(const Evas *e) | ||
1147 | { | ||
1148 | return evas_object_top_at_xy_get(e, e->pointer.x, e->pointer.y, EINA_TRUE, | ||
1149 | EINA_TRUE); | ||
1150 | } | ||
1151 | |||
1152 | EAPI Evas_Object * | ||
1153 | evas_object_top_in_rectangle_get(const Evas *e, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects) | ||
1154 | { | ||
1155 | Evas_Layer *lay; | ||
1156 | int xx, yy, ww, hh; | ||
1157 | |||
1158 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1159 | return NULL; | ||
1160 | MAGIC_CHECK_END(); | ||
1161 | xx = x; | ||
1162 | yy = y; | ||
1163 | ww = w; | ||
1164 | hh = h; | ||
1165 | //// xx = evas_coord_world_x_to_screen(e, x); | ||
1166 | //// yy = evas_coord_world_y_to_screen(e, y); | ||
1167 | //// ww = evas_coord_world_x_to_screen(e, w); | ||
1168 | //// hh = evas_coord_world_y_to_screen(e, h); | ||
1169 | if (ww < 1) ww = 1; | ||
1170 | if (hh < 1) hh = 1; | ||
1171 | EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay) | ||
1172 | { | ||
1173 | Evas_Object *obj; | ||
1174 | |||
1175 | EINA_INLIST_REVERSE_FOREACH(get_layer_objects(lay), obj) | ||
1176 | { | ||
1177 | if (obj->delete_me) continue; | ||
1178 | if ((!include_pass_events_objects) && | ||
1179 | (evas_event_passes_through(obj))) continue; | ||
1180 | if ((!include_hidden_objects) && (!obj->cur.visible)) continue; | ||
1181 | evas_object_clip_recalc(obj); | ||
1182 | if ((evas_object_is_in_output_rect(obj, xx, yy, ww, hh)) && | ||
1183 | (!obj->clip.clipees)) | ||
1184 | return obj; | ||
1185 | } | ||
1186 | } | ||
1187 | return NULL; | ||
1188 | } | ||
1189 | |||
1190 | EAPI Eina_List * | ||
1191 | evas_objects_at_xy_get(const Evas *e, Evas_Coord x, Evas_Coord y, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects) | ||
1192 | { | ||
1193 | Eina_List *in = NULL; | ||
1194 | Evas_Layer *lay; | ||
1195 | int xx, yy; | ||
1196 | |||
1197 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1198 | return NULL; | ||
1199 | MAGIC_CHECK_END(); | ||
1200 | xx = x; | ||
1201 | yy = y; | ||
1202 | //// xx = evas_coord_world_x_to_screen(e, x); | ||
1203 | //// yy = evas_coord_world_y_to_screen(e, y); | ||
1204 | EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay) | ||
1205 | { | ||
1206 | Evas_Object *obj; | ||
1207 | |||
1208 | EINA_INLIST_REVERSE_FOREACH(get_layer_objects(lay), obj) | ||
1209 | { | ||
1210 | if (obj->delete_me) continue; | ||
1211 | if ((!include_pass_events_objects) && | ||
1212 | (evas_event_passes_through(obj))) continue; | ||
1213 | if ((!include_hidden_objects) && (!obj->cur.visible)) continue; | ||
1214 | evas_object_clip_recalc(obj); | ||
1215 | if ((evas_object_is_in_output_rect(obj, xx, yy, 1, 1)) && | ||
1216 | (!obj->clip.clipees)) | ||
1217 | in = eina_list_prepend(in, obj); | ||
1218 | } | ||
1219 | } | ||
1220 | return in; | ||
1221 | } | ||
1222 | |||
1223 | /** | ||
1224 | * Retrieves the objects in the given rectangle region | ||
1225 | * @param e The given evas object. | ||
1226 | * @param x The horizontal coordinate. | ||
1227 | * @param y The vertical coordinate. | ||
1228 | * @param w The width size. | ||
1229 | * @param h The height size. | ||
1230 | * @param include_pass_events_objects Boolean Flag to include or not pass events objects | ||
1231 | * @param include_hidden_objects Boolean Flag to include or not hidden objects | ||
1232 | * @return The list of evas object in the rectangle region. | ||
1233 | * | ||
1234 | */ | ||
1235 | EAPI Eina_List * | ||
1236 | evas_objects_in_rectangle_get(const Evas *e, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool include_pass_events_objects, Eina_Bool include_hidden_objects) | ||
1237 | { | ||
1238 | Eina_List *in = NULL; | ||
1239 | Evas_Layer *lay; | ||
1240 | int xx, yy, ww, hh; | ||
1241 | |||
1242 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1243 | return NULL; | ||
1244 | MAGIC_CHECK_END(); | ||
1245 | xx = x; | ||
1246 | yy = y; | ||
1247 | ww = w; | ||
1248 | hh = h; | ||
1249 | //// xx = evas_coord_world_x_to_screen(e, x); | ||
1250 | //// yy = evas_coord_world_y_to_screen(e, y); | ||
1251 | //// ww = evas_coord_world_x_to_screen(e, w); | ||
1252 | //// hh = evas_coord_world_y_to_screen(e, h); | ||
1253 | if (ww < 1) ww = 1; | ||
1254 | if (hh < 1) hh = 1; | ||
1255 | EINA_INLIST_REVERSE_FOREACH((EINA_INLIST_GET(e->layers)), lay) | ||
1256 | { | ||
1257 | Evas_Object *obj; | ||
1258 | |||
1259 | EINA_INLIST_REVERSE_FOREACH(get_layer_objects(lay), obj) | ||
1260 | { | ||
1261 | if (obj->delete_me) continue; | ||
1262 | if ((!include_pass_events_objects) && | ||
1263 | (evas_event_passes_through(obj))) continue; | ||
1264 | if ((!include_hidden_objects) && (!obj->cur.visible)) continue; | ||
1265 | evas_object_clip_recalc(obj); | ||
1266 | if ((evas_object_is_in_output_rect(obj, xx, yy, ww, hh)) && | ||
1267 | (!obj->clip.clipees)) | ||
1268 | in = eina_list_prepend(in, obj); | ||
1269 | } | ||
1270 | } | ||
1271 | return in; | ||
1272 | } | ||
1273 | |||
1274 | EAPI const char * | ||
1275 | evas_object_type_get(const Evas_Object *obj) | ||
1276 | { | ||
1277 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1278 | return NULL; | ||
1279 | MAGIC_CHECK_END(); | ||
1280 | if (obj->delete_me) return ""; | ||
1281 | return obj->type; | ||
1282 | } | ||
1283 | |||
1284 | EAPI void | ||
1285 | evas_object_precise_is_inside_set(Evas_Object *obj, Eina_Bool precise) | ||
1286 | { | ||
1287 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1288 | return; | ||
1289 | MAGIC_CHECK_END(); | ||
1290 | obj->precise_is_inside = precise; | ||
1291 | } | ||
1292 | |||
1293 | EAPI Eina_Bool | ||
1294 | evas_object_precise_is_inside_get(const Evas_Object *obj) | ||
1295 | { | ||
1296 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1297 | return 0; | ||
1298 | MAGIC_CHECK_END(); | ||
1299 | return obj->precise_is_inside; | ||
1300 | } | ||
1301 | |||
1302 | EAPI void | ||
1303 | evas_object_static_clip_set(Evas_Object *obj, Eina_Bool is_static_clip) | ||
1304 | { | ||
1305 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1306 | return; | ||
1307 | MAGIC_CHECK_END(); | ||
1308 | obj->is_static_clip = is_static_clip; | ||
1309 | } | ||
1310 | |||
1311 | EAPI Eina_Bool | ||
1312 | evas_object_static_clip_get(const Evas_Object *obj) | ||
1313 | { | ||
1314 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1315 | return 0; | ||
1316 | MAGIC_CHECK_END(); | ||
1317 | return obj->is_static_clip; | ||
1318 | } | ||
1319 | |||
diff --git a/libraries/evas/src/lib/canvas/evas_object_polygon.c b/libraries/evas/src/lib/canvas/evas_object_polygon.c new file mode 100644 index 0000000..cbc1802 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_polygon.c | |||
@@ -0,0 +1,554 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* private magic number for polygon objects */ | ||
5 | static const char o_type[] = "polygon"; | ||
6 | |||
7 | /* private struct for line object internal data */ | ||
8 | typedef struct _Evas_Object_Polygon Evas_Object_Polygon; | ||
9 | typedef struct _Evas_Polygon_Point Evas_Polygon_Point; | ||
10 | |||
11 | struct _Evas_Object_Polygon | ||
12 | { | ||
13 | DATA32 magic; | ||
14 | Eina_List *points; | ||
15 | void *engine_data; | ||
16 | struct { | ||
17 | int x, y; | ||
18 | } offset; | ||
19 | Evas_Coord_Rectangle geometry; | ||
20 | char changed : 1; | ||
21 | }; | ||
22 | |||
23 | struct _Evas_Polygon_Point | ||
24 | { | ||
25 | Evas_Coord x, y; | ||
26 | }; | ||
27 | |||
28 | /* private methods for polygon objects */ | ||
29 | static void evas_object_polygon_init(Evas_Object *obj); | ||
30 | static void *evas_object_polygon_new(void); | ||
31 | static void evas_object_polygon_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y); | ||
32 | static void evas_object_polygon_free(Evas_Object *obj); | ||
33 | static void evas_object_polygon_render_pre(Evas_Object *obj); | ||
34 | static void evas_object_polygon_render_post(Evas_Object *obj); | ||
35 | |||
36 | static unsigned int evas_object_polygon_id_get(Evas_Object *obj); | ||
37 | static unsigned int evas_object_polygon_visual_id_get(Evas_Object *obj); | ||
38 | static void *evas_object_polygon_engine_data_get(Evas_Object *obj); | ||
39 | |||
40 | static int evas_object_polygon_is_opaque(Evas_Object *obj); | ||
41 | static int evas_object_polygon_was_opaque(Evas_Object *obj); | ||
42 | static int evas_object_polygon_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y); | ||
43 | static int evas_object_polygon_was_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y); | ||
44 | |||
45 | static const Evas_Object_Func object_func = | ||
46 | { | ||
47 | /* methods (compulsory) */ | ||
48 | evas_object_polygon_free, | ||
49 | evas_object_polygon_render, | ||
50 | evas_object_polygon_render_pre, | ||
51 | evas_object_polygon_render_post, | ||
52 | evas_object_polygon_id_get, | ||
53 | evas_object_polygon_visual_id_get, | ||
54 | evas_object_polygon_engine_data_get, | ||
55 | /* these are optional. NULL = nothing */ | ||
56 | NULL, | ||
57 | NULL, | ||
58 | NULL, | ||
59 | NULL, | ||
60 | evas_object_polygon_is_opaque, | ||
61 | evas_object_polygon_was_opaque, | ||
62 | evas_object_polygon_is_inside, | ||
63 | evas_object_polygon_was_inside, | ||
64 | NULL, | ||
65 | NULL, | ||
66 | NULL, | ||
67 | NULL, | ||
68 | NULL | ||
69 | }; | ||
70 | |||
71 | /* the actual api call to add a rect */ | ||
72 | /* it has no other api calls as all properties are standard */ | ||
73 | |||
74 | EVAS_MEMPOOL(_mp_obj); | ||
75 | |||
76 | EAPI Evas_Object * | ||
77 | evas_object_polygon_add(Evas *e) | ||
78 | { | ||
79 | Evas_Object *obj; | ||
80 | |||
81 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
82 | return NULL; | ||
83 | MAGIC_CHECK_END(); | ||
84 | obj = evas_object_new(e); | ||
85 | evas_object_polygon_init(obj); | ||
86 | evas_object_inject(obj, e); | ||
87 | return obj; | ||
88 | } | ||
89 | |||
90 | EAPI void | ||
91 | evas_object_polygon_point_add(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
92 | { | ||
93 | Evas_Object_Polygon *o; | ||
94 | Evas_Polygon_Point *p; | ||
95 | Evas_Coord min_x, max_x, min_y, max_y; | ||
96 | int is, was = 0; | ||
97 | |||
98 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
99 | return; | ||
100 | MAGIC_CHECK_END(); | ||
101 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
102 | MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON); | ||
103 | return; | ||
104 | MAGIC_CHECK_END(); | ||
105 | |||
106 | if (obj->layer->evas->events_frozen <= 0) | ||
107 | { | ||
108 | if (!evas_event_passes_through(obj) && | ||
109 | !evas_event_freezes_through(obj)) | ||
110 | was = evas_object_is_in_output_rect(obj, | ||
111 | obj->layer->evas->pointer.x, | ||
112 | obj->layer->evas->pointer.y, | ||
113 | 1, 1); | ||
114 | } | ||
115 | if (!o->points) | ||
116 | { | ||
117 | o->offset.x = obj->cur.geometry.x; | ||
118 | o->offset.y = obj->cur.geometry.y; | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | /* Update all points and take offset into account. */ | ||
123 | Eina_List *over; | ||
124 | |||
125 | EINA_LIST_FOREACH(o->points, over, p) | ||
126 | { | ||
127 | p->x += o->offset.x; | ||
128 | p->y += o->offset.y; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | p = malloc(sizeof(Evas_Polygon_Point)); | ||
133 | if (!p) return; | ||
134 | p->x = x + o->offset.x; | ||
135 | p->y = y + o->offset.y; | ||
136 | |||
137 | if (!o->points) | ||
138 | { | ||
139 | obj->cur.geometry.x = p->x; | ||
140 | obj->cur.geometry.y = p->y; | ||
141 | obj->cur.geometry.w = 2; | ||
142 | obj->cur.geometry.h = 2; | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | if (p->x < obj->cur.geometry.x) min_x = p->x; | ||
147 | else min_x = obj->cur.geometry.x; | ||
148 | if (p->x > (obj->cur.geometry.x + obj->cur.geometry.w - 2)) | ||
149 | max_x = p->x; | ||
150 | else max_x = obj->cur.geometry.x + obj->cur.geometry.w - 2; | ||
151 | if (p->y < obj->cur.geometry.y) min_y = p->y; | ||
152 | else min_y = obj->cur.geometry.y; | ||
153 | if (p->y > (obj->cur.geometry.y + obj->cur.geometry.h - 2)) | ||
154 | max_y = p->y; | ||
155 | else max_y = obj->cur.geometry.y + obj->cur.geometry.h - 2; | ||
156 | obj->cur.geometry.x = min_x; | ||
157 | obj->cur.geometry.y = min_y; | ||
158 | obj->cur.geometry.w = max_x - min_x + 2; | ||
159 | obj->cur.geometry.h = max_y - min_y + 2; | ||
160 | } | ||
161 | o->points = eina_list_append(o->points, p); | ||
162 | |||
163 | o->geometry = obj->cur.geometry; | ||
164 | o->offset.x = 0; | ||
165 | o->offset.y = 0; | ||
166 | |||
167 | //// obj->cur.cache.geometry.validity = 0; | ||
168 | o->changed = EINA_TRUE; | ||
169 | evas_object_change(obj); | ||
170 | evas_object_clip_dirty(obj); | ||
171 | evas_object_coords_recalc(obj); | ||
172 | if (obj->layer->evas->events_frozen <= 0) | ||
173 | { | ||
174 | is = evas_object_is_in_output_rect(obj, | ||
175 | obj->layer->evas->pointer.x, | ||
176 | obj->layer->evas->pointer.y, 1, 1); | ||
177 | if (!evas_event_passes_through(obj) && | ||
178 | !evas_event_freezes_through(obj) ) | ||
179 | { | ||
180 | if ((is ^ was) && obj->cur.visible) | ||
181 | evas_event_feed_mouse_move(obj->layer->evas, | ||
182 | obj->layer->evas->pointer.x, | ||
183 | obj->layer->evas->pointer.y, | ||
184 | obj->layer->evas->last_timestamp, | ||
185 | NULL); | ||
186 | } | ||
187 | } | ||
188 | evas_object_inform_call_move(obj); | ||
189 | evas_object_inform_call_resize(obj); | ||
190 | } | ||
191 | |||
192 | EAPI void | ||
193 | evas_object_polygon_points_clear(Evas_Object *obj) | ||
194 | { | ||
195 | Evas_Object_Polygon *o; | ||
196 | int is, was; | ||
197 | |||
198 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
199 | return; | ||
200 | MAGIC_CHECK_END(); | ||
201 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
202 | MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON); | ||
203 | return; | ||
204 | MAGIC_CHECK_END(); | ||
205 | was = evas_object_is_in_output_rect(obj, | ||
206 | obj->layer->evas->pointer.x, | ||
207 | obj->layer->evas->pointer.y, 1, 1); | ||
208 | while (o->points) | ||
209 | { | ||
210 | free(o->points->data); | ||
211 | o->points = eina_list_remove(o->points, o->points->data); | ||
212 | } | ||
213 | obj->cur.geometry.x = 0; | ||
214 | obj->cur.geometry.y = 0; | ||
215 | obj->cur.geometry.w = 0; | ||
216 | obj->cur.geometry.h = 0; | ||
217 | //// obj->cur.cache.geometry.validity = 0; | ||
218 | o->changed = EINA_TRUE; | ||
219 | evas_object_change(obj); | ||
220 | evas_object_clip_dirty(obj); | ||
221 | evas_object_coords_recalc(obj); | ||
222 | is = evas_object_is_in_output_rect(obj, | ||
223 | obj->layer->evas->pointer.x, | ||
224 | obj->layer->evas->pointer.y, 1, 1); | ||
225 | if ((is || was) && obj->cur.visible) | ||
226 | evas_event_feed_mouse_move(obj->layer->evas, | ||
227 | obj->layer->evas->pointer.x, | ||
228 | obj->layer->evas->pointer.y, | ||
229 | obj->layer->evas->last_timestamp, | ||
230 | NULL); | ||
231 | evas_object_inform_call_move(obj); | ||
232 | evas_object_inform_call_resize(obj); | ||
233 | } | ||
234 | |||
235 | /* all nice and private */ | ||
236 | static void | ||
237 | evas_object_polygon_init(Evas_Object *obj) | ||
238 | { | ||
239 | /* alloc image ob, setup methods and default values */ | ||
240 | obj->object_data = evas_object_polygon_new(); | ||
241 | /* set up default settings for this kind of object */ | ||
242 | obj->cur.color.r = 255; | ||
243 | obj->cur.color.g = 255; | ||
244 | obj->cur.color.b = 255; | ||
245 | obj->cur.color.a = 255; | ||
246 | obj->cur.geometry.x = 0; | ||
247 | obj->cur.geometry.y = 0; | ||
248 | obj->cur.geometry.w = 0; | ||
249 | obj->cur.geometry.h = 0; | ||
250 | obj->cur.layer = 0; | ||
251 | /* set up object-specific settings */ | ||
252 | obj->prev = obj->cur; | ||
253 | /* set up methods (compulsory) */ | ||
254 | obj->func = &object_func; | ||
255 | obj->type = o_type; | ||
256 | } | ||
257 | |||
258 | static void * | ||
259 | evas_object_polygon_new(void) | ||
260 | { | ||
261 | Evas_Object_Polygon *o; | ||
262 | |||
263 | /* alloc obj private data */ | ||
264 | EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_polygon", Evas_Object_Polygon, 32, NULL); | ||
265 | o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Polygon); | ||
266 | if (!o) return NULL; | ||
267 | EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Polygon); | ||
268 | o->magic = MAGIC_OBJ_POLYGON; | ||
269 | return o; | ||
270 | } | ||
271 | |||
272 | static void | ||
273 | evas_object_polygon_free(Evas_Object *obj) | ||
274 | { | ||
275 | Evas_Object_Polygon *o; | ||
276 | |||
277 | /* frees private object data. very simple here */ | ||
278 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
279 | MAGIC_CHECK(o, Evas_Object_Polygon, MAGIC_OBJ_POLYGON); | ||
280 | return; | ||
281 | MAGIC_CHECK_END(); | ||
282 | /* free obj */ | ||
283 | while (o->points) | ||
284 | { | ||
285 | free(o->points->data); | ||
286 | o->points = eina_list_remove(o->points, o->points->data); | ||
287 | } | ||
288 | o->engine_data = obj->layer->evas->engine.func->polygon_points_clear(obj->layer->evas->engine.data.output, | ||
289 | obj->layer->evas->engine.data.context, | ||
290 | o->engine_data); | ||
291 | o->magic = 0; | ||
292 | EVAS_MEMPOOL_FREE(_mp_obj, o); | ||
293 | } | ||
294 | |||
295 | static void | ||
296 | evas_object_polygon_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y) | ||
297 | { | ||
298 | Evas_Object_Polygon *o; | ||
299 | Eina_List *l; | ||
300 | Evas_Polygon_Point *p; | ||
301 | |||
302 | /* render object to surface with context, and offxet by x,y */ | ||
303 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
304 | obj->layer->evas->engine.func->context_color_set(output, | ||
305 | context, | ||
306 | obj->cur.cache.clip.r, | ||
307 | obj->cur.cache.clip.g, | ||
308 | obj->cur.cache.clip.b, | ||
309 | obj->cur.cache.clip.a); | ||
310 | obj->layer->evas->engine.func->context_multiplier_unset(output, | ||
311 | context); | ||
312 | obj->layer->evas->engine.func->context_render_op_set(output, context, | ||
313 | obj->cur.render_op); | ||
314 | if (o->changed) | ||
315 | { | ||
316 | o->engine_data = obj->layer->evas->engine.func->polygon_points_clear(obj->layer->evas->engine.data.output, | ||
317 | obj->layer->evas->engine.data.context, | ||
318 | o->engine_data); | ||
319 | EINA_LIST_FOREACH(o->points, l, p) | ||
320 | { | ||
321 | //px = evas_coord_world_x_to_screen(obj->layer->evas, p->x); | ||
322 | //py = evas_coord_world_y_to_screen(obj->layer->evas, p->y); | ||
323 | o->engine_data = obj->layer->evas->engine.func->polygon_point_add(obj->layer->evas->engine.data.output, | ||
324 | obj->layer->evas->engine.data.context, | ||
325 | o->engine_data, | ||
326 | p->x, p->y); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | if (o->engine_data) | ||
331 | obj->layer->evas->engine.func->polygon_draw(output, | ||
332 | context, | ||
333 | surface, | ||
334 | o->engine_data, | ||
335 | o->offset.x + x, o->offset.y + y); | ||
336 | } | ||
337 | |||
338 | static void | ||
339 | evas_object_polygon_render_pre(Evas_Object *obj) | ||
340 | { | ||
341 | Evas_Object_Polygon *o; | ||
342 | int is_v, was_v; | ||
343 | |||
344 | /* dont pre-render the obj twice! */ | ||
345 | if (obj->pre_render_done) return; | ||
346 | obj->pre_render_done = 1; | ||
347 | /* pre-render phase. this does anything an object needs to do just before */ | ||
348 | /* rendering. this could mean loading the image data, retrieving it from */ | ||
349 | /* elsewhere, decoding video etc. */ | ||
350 | /* then when this is done the object needs to figure if it changed and */ | ||
351 | /* if so what and where and add the appropriate redraw lines */ | ||
352 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
353 | /* if someone is clipping this obj - go calculate the clipper */ | ||
354 | if (obj->cur.clipper) | ||
355 | { | ||
356 | if (obj->cur.cache.clip.dirty) | ||
357 | evas_object_clip_recalc(obj->cur.clipper); | ||
358 | obj->cur.clipper->func->render_pre(obj->cur.clipper); | ||
359 | } | ||
360 | /* now figure what changed and add draw rects */ | ||
361 | /* if it just became visible or invisible */ | ||
362 | is_v = evas_object_is_visible(obj); | ||
363 | was_v = evas_object_was_visible(obj); | ||
364 | if (is_v != was_v) | ||
365 | { | ||
366 | evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v); | ||
367 | goto done; | ||
368 | } | ||
369 | if ((obj->cur.map != obj->prev.map) || | ||
370 | (obj->cur.usemap != obj->prev.usemap)) | ||
371 | { | ||
372 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
373 | goto done; | ||
374 | } | ||
375 | /* it's not visible - we accounted for it appearing or not so just abort */ | ||
376 | if (!is_v) goto done; | ||
377 | /* clipper changed this is in addition to anything else for obj */ | ||
378 | evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj); | ||
379 | /* if we restacked (layer or just within a layer) */ | ||
380 | if (obj->restack) | ||
381 | { | ||
382 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
383 | goto done; | ||
384 | } | ||
385 | /* if it changed render op */ | ||
386 | if (obj->cur.render_op != obj->prev.render_op) | ||
387 | { | ||
388 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
389 | goto done; | ||
390 | } | ||
391 | /* if it changed color */ | ||
392 | if ((obj->cur.color.r != obj->prev.color.r) || | ||
393 | (obj->cur.color.g != obj->prev.color.g) || | ||
394 | (obj->cur.color.b != obj->prev.color.b) || | ||
395 | (obj->cur.color.a != obj->prev.color.a)) | ||
396 | { | ||
397 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
398 | goto done; | ||
399 | } | ||
400 | /* if it changed geometry - and obviously not visibility or color */ | ||
401 | /* calculate differences since we have a constant color fill */ | ||
402 | /* we really only need to update the differences */ | ||
403 | if ((obj->cur.geometry.x != obj->prev.geometry.x) || | ||
404 | (obj->cur.geometry.y != obj->prev.geometry.y) || | ||
405 | (obj->cur.geometry.w != obj->prev.geometry.w) || | ||
406 | (obj->cur.geometry.h != obj->prev.geometry.h) || | ||
407 | (o->changed)) | ||
408 | { | ||
409 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
410 | goto done; | ||
411 | } | ||
412 | done: | ||
413 | if ((obj->cur.geometry.x != obj->prev.geometry.x) || | ||
414 | (obj->cur.geometry.y != obj->prev.geometry.y)) | ||
415 | { | ||
416 | if (!o->changed) | ||
417 | { | ||
418 | o->offset.x += obj->cur.geometry.x - obj->prev.geometry.x; | ||
419 | o->offset.y += obj->cur.geometry.y - obj->prev.geometry.y; | ||
420 | } | ||
421 | else | ||
422 | { | ||
423 | o->offset.x += obj->cur.geometry.x - o->geometry.x; | ||
424 | o->offset.y += obj->cur.geometry.y - o->geometry.y; | ||
425 | } | ||
426 | } | ||
427 | evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v); | ||
428 | } | ||
429 | |||
430 | static void | ||
431 | evas_object_polygon_render_post(Evas_Object *obj) | ||
432 | { | ||
433 | Evas_Object_Polygon *o; | ||
434 | |||
435 | /* this moves the current data to the previous state parts of the object */ | ||
436 | /* in whatever way is safest for the object. also if we don't need object */ | ||
437 | /* data anymore we can free it if the object deems this is a good idea */ | ||
438 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
439 | /* remove those pesky changes */ | ||
440 | evas_object_clip_changes_clean(obj); | ||
441 | /* move cur to prev safely for object data */ | ||
442 | obj->prev = obj->cur; | ||
443 | o->changed = 0; | ||
444 | } | ||
445 | |||
446 | static unsigned int evas_object_polygon_id_get(Evas_Object *obj) | ||
447 | { | ||
448 | Evas_Object_Polygon *o; | ||
449 | |||
450 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
451 | if (!o) return 0; | ||
452 | return MAGIC_OBJ_POLYGON; | ||
453 | } | ||
454 | |||
455 | static unsigned int evas_object_polygon_visual_id_get(Evas_Object *obj) | ||
456 | { | ||
457 | Evas_Object_Polygon *o; | ||
458 | |||
459 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
460 | if (!o) return 0; | ||
461 | return MAGIC_OBJ_SHAPE; | ||
462 | } | ||
463 | |||
464 | static void *evas_object_polygon_engine_data_get(Evas_Object *obj) | ||
465 | { | ||
466 | Evas_Object_Polygon *o; | ||
467 | |||
468 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
469 | if (!o) return NULL; | ||
470 | return o->engine_data; | ||
471 | } | ||
472 | |||
473 | static int | ||
474 | evas_object_polygon_is_opaque(Evas_Object *obj __UNUSED__) | ||
475 | { | ||
476 | /* this returns 1 if the internal object data implies that the object is */ | ||
477 | /* currently fully opaque over the entire line it occupies */ | ||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int | ||
482 | evas_object_polygon_was_opaque(Evas_Object *obj __UNUSED__) | ||
483 | { | ||
484 | /* this returns 1 if the internal object data implies that the object was */ | ||
485 | /* previously fully opaque over the entire line it occupies */ | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | /* We count the number of edges a "ray" 90 degs upwards from our point | ||
490 | * intersects with. If it's even, we are outside of the polygon, if it's odd, | ||
491 | * we are inside of it. */ | ||
492 | static int | ||
493 | evas_object_polygon_is_inside(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
494 | { | ||
495 | Evas_Object_Polygon *o; | ||
496 | int num_edges = 0; /* Number of edges we crossed */ | ||
497 | Eina_List *itr; | ||
498 | Evas_Polygon_Point *p; | ||
499 | |||
500 | o = (Evas_Object_Polygon *)(obj->object_data); | ||
501 | if (!o) return 0; | ||
502 | if (!o->points) return 0; | ||
503 | |||
504 | /* Adjust X and Y according to current geometry */ | ||
505 | x -= o->offset.x; | ||
506 | y -= o->offset.y; | ||
507 | |||
508 | if (eina_list_count(o->points) == 1) | ||
509 | { | ||
510 | p = eina_list_data_get(o->points); | ||
511 | return ((p->x == x) && (p->y == y)); | ||
512 | } | ||
513 | |||
514 | EINA_LIST_FOREACH(o->points, itr, p) | ||
515 | { | ||
516 | Evas_Coord line_y; | ||
517 | Eina_List *next = eina_list_next(itr); | ||
518 | Evas_Polygon_Point *p_next; | ||
519 | /* Get the next, or if there's no next, take the first */ | ||
520 | if (next) | ||
521 | { | ||
522 | p_next = eina_list_data_get(next); | ||
523 | } | ||
524 | else | ||
525 | { | ||
526 | p_next = eina_list_data_get(o->points); | ||
527 | } | ||
528 | |||
529 | /* Make sure that we are directly below the edge, | ||
530 | * and that p->x != p_next->x */ | ||
531 | if (((p->x < p_next->x) && (p->x <= x) && (x < p_next->x)) || | ||
532 | ((p->x > p_next->x) && (p_next->x < x) && (x <= p->x))) | ||
533 | { | ||
534 | line_y = ((double) (p->y - p_next->y) / | ||
535 | (double) (p->x - p_next->x)) * | ||
536 | (x - p_next->x) + p_next->y; | ||
537 | /* We crossed that edge if the line is directly above us */ | ||
538 | if (line_y < y) | ||
539 | num_edges++; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | /* Return true if num_edges is odd */ | ||
544 | return ((num_edges % 2) == 1); | ||
545 | } | ||
546 | |||
547 | static int | ||
548 | evas_object_polygon_was_inside(Evas_Object *obj __UNUSED__, Evas_Coord x __UNUSED__, Evas_Coord y __UNUSED__) | ||
549 | { | ||
550 | /* this returns 1 if the canvas co-ordinates were inside the object based */ | ||
551 | /* on object private data. not much use for rects, but for polys, images */ | ||
552 | /* and other complex objects it might be */ | ||
553 | return 1; | ||
554 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_rectangle.c b/libraries/evas/src/lib/canvas/evas_object_rectangle.c new file mode 100644 index 0000000..36678e7 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_rectangle.c | |||
@@ -0,0 +1,387 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* private magic number for rectangle objects */ | ||
5 | static const char o_type[] = "rectangle"; | ||
6 | |||
7 | const char *o_rect_type = o_type; | ||
8 | |||
9 | /* private struct for rectangle object internal data */ | ||
10 | typedef struct _Evas_Object_Rectangle Evas_Object_Rectangle; | ||
11 | |||
12 | struct _Evas_Object_Rectangle | ||
13 | { | ||
14 | DATA32 magic; | ||
15 | void *engine_data; | ||
16 | }; | ||
17 | |||
18 | /* private methods for rectangle objects */ | ||
19 | static void evas_object_rectangle_init(Evas_Object *obj); | ||
20 | static void *evas_object_rectangle_new(void); | ||
21 | static void evas_object_rectangle_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y); | ||
22 | static void evas_object_rectangle_free(Evas_Object *obj); | ||
23 | static void evas_object_rectangle_render_pre(Evas_Object *obj); | ||
24 | static void evas_object_rectangle_render_post(Evas_Object *obj); | ||
25 | |||
26 | static unsigned int evas_object_rectangle_id_get(Evas_Object *obj); | ||
27 | static unsigned int evas_object_rectangle_visual_id_get(Evas_Object *obj); | ||
28 | static void *evas_object_rectangle_engine_data_get(Evas_Object *obj); | ||
29 | |||
30 | static int evas_object_rectangle_is_opaque(Evas_Object *obj); | ||
31 | static int evas_object_rectangle_was_opaque(Evas_Object *obj); | ||
32 | |||
33 | #if 0 /* usless calls for a rect object. much more useful for images etc. */ | ||
34 | static void evas_object_rectangle_store(Evas_Object *obj); | ||
35 | static void evas_object_rectangle_unstore(Evas_Object *obj); | ||
36 | static int evas_object_rectangle_is_visible(Evas_Object *obj); | ||
37 | static int evas_object_rectangle_was_visible(Evas_Object *obj); | ||
38 | static int evas_object_rectangle_is_inside(Evas_Object *obj, double x, double y); | ||
39 | static int evas_object_rectangle_was_inside(Evas_Object *obj, double x, double y); | ||
40 | #endif | ||
41 | |||
42 | static const Evas_Object_Func object_func = | ||
43 | { | ||
44 | /* methods (compulsory) */ | ||
45 | evas_object_rectangle_free, | ||
46 | evas_object_rectangle_render, | ||
47 | evas_object_rectangle_render_pre, | ||
48 | evas_object_rectangle_render_post, | ||
49 | evas_object_rectangle_id_get, | ||
50 | evas_object_rectangle_visual_id_get, | ||
51 | evas_object_rectangle_engine_data_get, | ||
52 | /* these are optional. NULL = nothing */ | ||
53 | NULL, | ||
54 | NULL, | ||
55 | NULL, | ||
56 | NULL, | ||
57 | evas_object_rectangle_is_opaque, | ||
58 | evas_object_rectangle_was_opaque, | ||
59 | NULL, | ||
60 | NULL, | ||
61 | NULL, | ||
62 | NULL, | ||
63 | NULL, | ||
64 | NULL, | ||
65 | NULL | ||
66 | }; | ||
67 | |||
68 | /* the actual api call to add a rect */ | ||
69 | /* it has no other api calls as all properties are standard */ | ||
70 | |||
71 | EVAS_MEMPOOL(_mp_obj); | ||
72 | |||
73 | EAPI Evas_Object * | ||
74 | evas_object_rectangle_add(Evas *e) | ||
75 | { | ||
76 | Evas_Object *obj; | ||
77 | |||
78 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
79 | return NULL; | ||
80 | MAGIC_CHECK_END(); | ||
81 | obj = evas_object_new(e); | ||
82 | evas_object_rectangle_init(obj); | ||
83 | evas_object_inject(obj, e); | ||
84 | return obj; | ||
85 | } | ||
86 | |||
87 | /* all nice and private */ | ||
88 | static void | ||
89 | evas_object_rectangle_init(Evas_Object *obj) | ||
90 | { | ||
91 | /* alloc image ob, setup methods and default values */ | ||
92 | obj->object_data = evas_object_rectangle_new(); | ||
93 | /* set up default settings for this kind of object */ | ||
94 | obj->cur.color.r = 255; | ||
95 | obj->cur.color.g = 255; | ||
96 | obj->cur.color.b = 255; | ||
97 | obj->cur.color.a = 255; | ||
98 | obj->cur.geometry.x = 0; | ||
99 | obj->cur.geometry.y = 0; | ||
100 | obj->cur.geometry.w = 0; | ||
101 | obj->cur.geometry.h = 0; | ||
102 | obj->cur.layer = 0; | ||
103 | obj->cur.render_op = EVAS_RENDER_BLEND; | ||
104 | /* set up object-specific settings */ | ||
105 | obj->prev = obj->cur; | ||
106 | /* set up methods (compulsory) */ | ||
107 | obj->func = &object_func; | ||
108 | obj->type = o_type; | ||
109 | } | ||
110 | |||
111 | static void * | ||
112 | evas_object_rectangle_new(void) | ||
113 | { | ||
114 | Evas_Object_Rectangle *o; | ||
115 | |||
116 | /* alloc obj private data */ | ||
117 | EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_rectangle", Evas_Object_Rectangle, 256, NULL); | ||
118 | o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Rectangle); | ||
119 | if (!o) return NULL; | ||
120 | EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Rectangle); | ||
121 | o->magic = MAGIC_OBJ_RECTANGLE; | ||
122 | return o; | ||
123 | } | ||
124 | |||
125 | static void | ||
126 | evas_object_rectangle_free(Evas_Object *obj) | ||
127 | { | ||
128 | Evas_Object_Rectangle *o; | ||
129 | |||
130 | /* frees private object data. very simple here */ | ||
131 | o = (Evas_Object_Rectangle *)(obj->object_data); | ||
132 | MAGIC_CHECK(o, Evas_Object_Rectangle, MAGIC_OBJ_RECTANGLE); | ||
133 | return; | ||
134 | MAGIC_CHECK_END(); | ||
135 | /* free obj */ | ||
136 | o->magic = 0; | ||
137 | EVAS_MEMPOOL_FREE(_mp_obj, o); | ||
138 | } | ||
139 | |||
140 | static void | ||
141 | evas_object_rectangle_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y) | ||
142 | { | ||
143 | /* render object to surface with context, and offxet by x,y */ | ||
144 | obj->layer->evas->engine.func->context_color_set(output, | ||
145 | context, | ||
146 | obj->cur.cache.clip.r, | ||
147 | obj->cur.cache.clip.g, | ||
148 | obj->cur.cache.clip.b, | ||
149 | obj->cur.cache.clip.a); | ||
150 | obj->layer->evas->engine.func->context_multiplier_unset(output, | ||
151 | context); | ||
152 | obj->layer->evas->engine.func->context_render_op_set(output, context, | ||
153 | obj->cur.render_op); | ||
154 | obj->layer->evas->engine.func->rectangle_draw(output, | ||
155 | context, | ||
156 | surface, | ||
157 | obj->cur.geometry.x + x, | ||
158 | obj->cur.geometry.y + y, | ||
159 | obj->cur.geometry.w, | ||
160 | obj->cur.geometry.h); | ||
161 | //// obj->cur.cache.geometry.x + x, | ||
162 | //// obj->cur.cache.geometry.y + y, | ||
163 | //// obj->cur.cache.geometry.w, | ||
164 | //// obj->cur.cache.geometry.h); | ||
165 | } | ||
166 | |||
167 | static void | ||
168 | evas_object_rectangle_render_pre(Evas_Object *obj) | ||
169 | { | ||
170 | int is_v, was_v; | ||
171 | |||
172 | /* dont pre-render the obj twice! */ | ||
173 | if (obj->pre_render_done) return; | ||
174 | obj->pre_render_done = 1; | ||
175 | /* pre-render phase. this does anything an object needs to do just before */ | ||
176 | /* rendering. this could mean loading the image data, retrieving it from */ | ||
177 | /* elsewhere, decoding video etc. */ | ||
178 | /* then when this is done the object needs to figure if it changed and */ | ||
179 | /* if so what and where and add the appropriate redraw rectangles */ | ||
180 | /* if someone is clipping this obj - go calculate the clipper */ | ||
181 | if (obj->cur.clipper) | ||
182 | { | ||
183 | if (obj->cur.cache.clip.dirty) | ||
184 | evas_object_clip_recalc(obj->cur.clipper); | ||
185 | obj->cur.clipper->func->render_pre(obj->cur.clipper); | ||
186 | } | ||
187 | /* now figure what changed and add draw rects */ | ||
188 | /* if it just became visible or invisible */ | ||
189 | is_v = evas_object_is_visible(obj); | ||
190 | was_v = evas_object_was_visible(obj); | ||
191 | if (!(is_v | was_v)) goto done; | ||
192 | if (is_v != was_v) | ||
193 | { | ||
194 | evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v); | ||
195 | goto done; | ||
196 | } | ||
197 | if ((obj->cur.map != obj->prev.map) || | ||
198 | (obj->cur.usemap != obj->prev.usemap)) | ||
199 | { | ||
200 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
201 | goto done; | ||
202 | } | ||
203 | /* it's not visible - we accounted for it appearing or not so just abort */ | ||
204 | if (!is_v) goto done; | ||
205 | /* clipper changed this is in addition to anything else for obj */ | ||
206 | evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj); | ||
207 | /* if we restacked (layer or just within a layer) and don't clip anyone */ | ||
208 | if ((obj->restack) && (!obj->clip.clipees)) | ||
209 | { | ||
210 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
211 | goto done; | ||
212 | } | ||
213 | /* if it changed render op */ | ||
214 | if (obj->cur.render_op != obj->prev.render_op) | ||
215 | { | ||
216 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
217 | goto done; | ||
218 | } | ||
219 | /* if it changed color */ | ||
220 | if ((obj->cur.color.r != obj->prev.color.r) || | ||
221 | (obj->cur.color.g != obj->prev.color.g) || | ||
222 | (obj->cur.color.b != obj->prev.color.b) || | ||
223 | (obj->cur.color.a != obj->prev.color.a)) | ||
224 | { | ||
225 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
226 | goto done; | ||
227 | } | ||
228 | /* if it changed geometry - and obviously not visibility or color */ | ||
229 | /* calculate differences since we have a constant color fill */ | ||
230 | /* we really only need to update the differences */ | ||
231 | if ((obj->cur.geometry.x != obj->prev.geometry.x) || | ||
232 | (obj->cur.geometry.y != obj->prev.geometry.y) || | ||
233 | (obj->cur.geometry.w != obj->prev.geometry.w) || | ||
234 | (obj->cur.geometry.h != obj->prev.geometry.h)) | ||
235 | { | ||
236 | evas_rects_return_difference_rects(&obj->layer->evas->clip_changes, | ||
237 | obj->cur.geometry.x, | ||
238 | obj->cur.geometry.y, | ||
239 | obj->cur.geometry.w, | ||
240 | obj->cur.geometry.h, | ||
241 | obj->prev.geometry.x, | ||
242 | obj->prev.geometry.y, | ||
243 | obj->prev.geometry.w, | ||
244 | obj->prev.geometry.h); | ||
245 | //// rl = evas_rects_return_difference_rects(obj->cur.cache.geometry.x, | ||
246 | //// obj->cur.cache.geometry.y, | ||
247 | //// obj->cur.cache.geometry.w, | ||
248 | //// obj->cur.cache.geometry.h, | ||
249 | //// obj->prev.cache.geometry.x, | ||
250 | //// obj->prev.cache.geometry.y, | ||
251 | //// obj->prev.cache.geometry.w, | ||
252 | //// obj->prev.cache.geometry.h); | ||
253 | goto done; | ||
254 | } | ||
255 | /* it obviously didn't change - add a NO obscure - this "unupdates" this */ | ||
256 | /* area so if there were updates for it they get wiped. don't do it if we */ | ||
257 | /* arent fully opaque and we are visible */ | ||
258 | /* | ||
259 | if (evas_object_is_visible(obj) && | ||
260 | evas_object_is_opaque(obj) && | ||
261 | (!obj->clip.clipees)) | ||
262 | obj->layer->evas->engine.func->output_redraws_rect_del(obj->layer->evas->engine.data.output, | ||
263 | obj->cur.cache.clip.x, | ||
264 | obj->cur.cache.clip.y, | ||
265 | obj->cur.cache.clip.w, | ||
266 | obj->cur.cache.clip.h); | ||
267 | */ | ||
268 | done: | ||
269 | evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v); | ||
270 | } | ||
271 | |||
272 | static void | ||
273 | evas_object_rectangle_render_post(Evas_Object *obj) | ||
274 | { | ||
275 | |||
276 | /* this moves the current data to the previous state parts of the object */ | ||
277 | /* in whatever way is safest for the object. also if we don't need object */ | ||
278 | /* data anymore we can free it if the object deems this is a good idea */ | ||
279 | /* remove those pesky changes */ | ||
280 | evas_object_clip_changes_clean(obj); | ||
281 | /* move cur to prev safely for object data */ | ||
282 | obj->prev = obj->cur; | ||
283 | } | ||
284 | |||
285 | static int | ||
286 | evas_object_rectangle_is_opaque(Evas_Object *obj) | ||
287 | { | ||
288 | /* this returns 1 if the internal object data implies that the object is */ | ||
289 | /* currently fully opaque over the entire rectangle it occupies */ | ||
290 | if ((obj->cur.map) && (obj->cur.usemap)) return 0; | ||
291 | if (obj->cur.render_op == EVAS_RENDER_COPY) | ||
292 | return 1; | ||
293 | if (obj->cur.render_op != EVAS_RENDER_BLEND) | ||
294 | return 0; | ||
295 | return 1; | ||
296 | } | ||
297 | |||
298 | static int | ||
299 | evas_object_rectangle_was_opaque(Evas_Object *obj) | ||
300 | { | ||
301 | /* this returns 1 if the internal object data implies that the object was */ | ||
302 | /* previously fully opaque over the entire rectangle it occupies */ | ||
303 | if (obj->prev.render_op == EVAS_RENDER_COPY) | ||
304 | return 1; | ||
305 | if (obj->prev.render_op != EVAS_RENDER_BLEND) | ||
306 | return 0; | ||
307 | return 1; | ||
308 | } | ||
309 | |||
310 | static unsigned int evas_object_rectangle_id_get(Evas_Object *obj) | ||
311 | { | ||
312 | Evas_Object_Rectangle *o; | ||
313 | |||
314 | o = (Evas_Object_Rectangle *)(obj->object_data); | ||
315 | if (!o) return 0; | ||
316 | return MAGIC_OBJ_RECTANGLE; | ||
317 | } | ||
318 | |||
319 | static unsigned int evas_object_rectangle_visual_id_get(Evas_Object *obj) | ||
320 | { | ||
321 | Evas_Object_Rectangle *o; | ||
322 | |||
323 | o = (Evas_Object_Rectangle *)(obj->object_data); | ||
324 | if (!o) return 0; | ||
325 | return MAGIC_OBJ_SHAPE; | ||
326 | } | ||
327 | |||
328 | static void *evas_object_rectangle_engine_data_get(Evas_Object *obj) | ||
329 | { | ||
330 | Evas_Object_Rectangle *o; | ||
331 | |||
332 | o = (Evas_Object_Rectangle *)(obj->object_data); | ||
333 | if (!o) return NULL; | ||
334 | return o->engine_data; | ||
335 | } | ||
336 | |||
337 | |||
338 | #if 0 /* usless calls for a rect object. much more useful for images etc. */ | ||
339 | static void | ||
340 | evas_object_rectangle_store(Evas_Object *obj) | ||
341 | { | ||
342 | /* store... nothing for rectangle objects... it's a bit silly */ | ||
343 | /* but for others that may have expensive caluclations to do to */ | ||
344 | /* generate the object data, hint that they might want to be pre-calced */ | ||
345 | /* once and stored */ | ||
346 | } | ||
347 | |||
348 | static void | ||
349 | evas_object_rectangle_unstore(Evas_Object *obj) | ||
350 | { | ||
351 | /* store... nothing for rectangle objects... it's a bit silly */ | ||
352 | } | ||
353 | |||
354 | static int | ||
355 | evas_object_rectangle_is_visible(Evas_Object *obj) | ||
356 | { | ||
357 | /* this returns 1 if the internal object data would imply that it is */ | ||
358 | /* visible (ie drawing it draws something. this is not to do with events */ | ||
359 | return 1; | ||
360 | } | ||
361 | |||
362 | static int | ||
363 | evas_object_rectangle_was_visible(Evas_Object *obj) | ||
364 | { | ||
365 | /* this returns 1 if the internal object data would imply that it was */ | ||
366 | /* visible (ie drawing it draws something. this is not to do with events */ | ||
367 | return 1; | ||
368 | } | ||
369 | |||
370 | static int | ||
371 | evas_object_rectangle_is_inside(Evas_Object *obj, double x, double y) | ||
372 | { | ||
373 | /* this returns 1 if the canvas co-ordinates are inside the object based */ | ||
374 | /* on object private data. not much use for rects, but for polys, images */ | ||
375 | /* and other complex objects it might be */ | ||
376 | return 1; | ||
377 | } | ||
378 | |||
379 | static int | ||
380 | evas_object_rectangle_was_inside(Evas_Object *obj, double x, double y) | ||
381 | { | ||
382 | /* this returns 1 if the canvas co-ordinates were inside the object based */ | ||
383 | /* on object private data. not much use for rects, but for polys, images */ | ||
384 | /* and other complex objects it might be */ | ||
385 | return 1; | ||
386 | } | ||
387 | #endif | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_smart.c b/libraries/evas/src/lib/canvas/evas_object_smart.c new file mode 100644 index 0000000..a7dfcdf --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_smart.c | |||
@@ -0,0 +1,920 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | typedef struct _Evas_Object_Smart Evas_Object_Smart; | ||
5 | typedef struct _Evas_Smart_Callback Evas_Smart_Callback; | ||
6 | |||
7 | struct _Evas_Object_Smart | ||
8 | { | ||
9 | DATA32 magic; | ||
10 | void *engine_data; | ||
11 | void *data; | ||
12 | Eina_List *callbacks; | ||
13 | Eina_Inlist *contained; | ||
14 | Evas_Smart_Cb_Description_Array callbacks_descriptions; | ||
15 | int walking_list; | ||
16 | Eina_Bool deletions_waiting : 1; | ||
17 | Eina_Bool need_recalculate : 1; | ||
18 | }; | ||
19 | |||
20 | struct _Evas_Smart_Callback | ||
21 | { | ||
22 | const char *event; | ||
23 | Evas_Smart_Cb func; | ||
24 | void *func_data; | ||
25 | Evas_Callback_Priority priority; | ||
26 | char delete_me : 1; | ||
27 | }; | ||
28 | |||
29 | /* private methods for smart objects */ | ||
30 | static void evas_object_smart_callbacks_clear(Evas_Object *obj); | ||
31 | static void evas_object_smart_init(Evas_Object *obj); | ||
32 | static void *evas_object_smart_new(void); | ||
33 | static void evas_object_smart_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y); | ||
34 | static void evas_object_smart_free(Evas_Object *obj); | ||
35 | static void evas_object_smart_render_pre(Evas_Object *obj); | ||
36 | static void evas_object_smart_render_post(Evas_Object *obj); | ||
37 | |||
38 | static unsigned int evas_object_smart_id_get(Evas_Object *obj); | ||
39 | static unsigned int evas_object_smart_visual_id_get(Evas_Object *obj); | ||
40 | static void *evas_object_smart_engine_data_get(Evas_Object *obj); | ||
41 | |||
42 | static const Evas_Object_Func object_func = | ||
43 | { | ||
44 | /* methods (compulsory) */ | ||
45 | evas_object_smart_free, | ||
46 | evas_object_smart_render, | ||
47 | evas_object_smart_render_pre, | ||
48 | evas_object_smart_render_post, | ||
49 | evas_object_smart_id_get, | ||
50 | evas_object_smart_visual_id_get, | ||
51 | evas_object_smart_engine_data_get, | ||
52 | /* these are optional. NULL = nothing */ | ||
53 | NULL, | ||
54 | NULL, | ||
55 | NULL, | ||
56 | NULL, | ||
57 | NULL, | ||
58 | NULL, | ||
59 | NULL, | ||
60 | NULL, | ||
61 | NULL, | ||
62 | NULL, | ||
63 | NULL, | ||
64 | NULL, | ||
65 | NULL | ||
66 | }; | ||
67 | |||
68 | EVAS_MEMPOOL(_mp_obj); | ||
69 | EVAS_MEMPOOL(_mp_cb); | ||
70 | |||
71 | /* public funcs */ | ||
72 | EAPI void | ||
73 | evas_object_smart_data_set(Evas_Object *obj, void *data) | ||
74 | { | ||
75 | Evas_Object_Smart *o; | ||
76 | |||
77 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
78 | return; | ||
79 | MAGIC_CHECK_END(); | ||
80 | o = (Evas_Object_Smart *)(obj->object_data); | ||
81 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
82 | return; | ||
83 | MAGIC_CHECK_END(); | ||
84 | o->data = data; | ||
85 | } | ||
86 | |||
87 | EAPI void * | ||
88 | evas_object_smart_data_get(const Evas_Object *obj) | ||
89 | { | ||
90 | Evas_Object_Smart *o; | ||
91 | |||
92 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
93 | return NULL; | ||
94 | MAGIC_CHECK_END(); | ||
95 | o = (Evas_Object_Smart *)(obj->object_data); | ||
96 | if (!o) return NULL; | ||
97 | return o->data; | ||
98 | } | ||
99 | |||
100 | EAPI Evas_Smart * | ||
101 | evas_object_smart_smart_get(const Evas_Object *obj) | ||
102 | { | ||
103 | Evas_Object_Smart *o; | ||
104 | |||
105 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
106 | return NULL; | ||
107 | MAGIC_CHECK_END(); | ||
108 | o = (Evas_Object_Smart *)(obj->object_data); | ||
109 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
110 | return NULL; | ||
111 | MAGIC_CHECK_END(); | ||
112 | return obj->smart.smart; | ||
113 | } | ||
114 | |||
115 | EAPI void | ||
116 | evas_object_smart_member_add(Evas_Object *obj, Evas_Object *smart_obj) | ||
117 | { | ||
118 | Evas_Object_Smart *o; | ||
119 | |||
120 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
121 | return; | ||
122 | MAGIC_CHECK_END(); | ||
123 | MAGIC_CHECK(smart_obj, Evas_Object, MAGIC_OBJ); | ||
124 | return; | ||
125 | MAGIC_CHECK_END(); | ||
126 | o = (Evas_Object_Smart *)(smart_obj->object_data); | ||
127 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
128 | return; | ||
129 | MAGIC_CHECK_END(); | ||
130 | |||
131 | if (obj->delete_me) | ||
132 | { | ||
133 | CRIT("Adding deleted object %p to smart obj %p", obj, smart_obj); | ||
134 | abort(); | ||
135 | return; | ||
136 | } | ||
137 | if (smart_obj->delete_me) | ||
138 | { | ||
139 | CRIT("Adding object %p to deleted smart obj %p", obj, smart_obj); | ||
140 | abort(); | ||
141 | return; | ||
142 | } | ||
143 | if (!smart_obj->layer) | ||
144 | { | ||
145 | CRIT("No evas surface associated with smart object (%p)", smart_obj); | ||
146 | abort(); | ||
147 | return; | ||
148 | } | ||
149 | if ((obj->layer && smart_obj->layer) && | ||
150 | (obj->layer->evas != smart_obj->layer->evas)) | ||
151 | { | ||
152 | CRIT("Adding object %p from Evas (%p) from another Evas (%p)", obj, obj->layer->evas, smart_obj->layer->evas); | ||
153 | abort(); | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | if (obj->smart.parent == smart_obj) return; | ||
158 | |||
159 | if (obj->smart.parent) evas_object_smart_member_del(obj); | ||
160 | |||
161 | evas_object_release(obj, 1); | ||
162 | obj->layer = smart_obj->layer; | ||
163 | obj->cur.layer = obj->layer->layer; | ||
164 | obj->layer->usage++; | ||
165 | obj->smart.parent = smart_obj; | ||
166 | o->contained = eina_inlist_append(o->contained, EINA_INLIST_GET(obj)); | ||
167 | evas_object_smart_member_cache_invalidate(obj, EINA_TRUE, EINA_TRUE); | ||
168 | obj->restack = 1; | ||
169 | evas_object_change(obj); | ||
170 | evas_object_mapped_clip_across_mark(obj); | ||
171 | if (smart_obj->smart.smart->smart_class->member_add) | ||
172 | smart_obj->smart.smart->smart_class->member_add(smart_obj, obj); | ||
173 | } | ||
174 | |||
175 | EAPI void | ||
176 | evas_object_smart_member_del(Evas_Object *obj) | ||
177 | { | ||
178 | Evas_Object_Smart *o; | ||
179 | Evas_Object *smart_obj; | ||
180 | |||
181 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
182 | return; | ||
183 | MAGIC_CHECK_END(); | ||
184 | |||
185 | if (!obj->smart.parent) return; | ||
186 | |||
187 | smart_obj = obj->smart.parent; | ||
188 | if (smart_obj->smart.smart->smart_class->member_del) | ||
189 | smart_obj->smart.smart->smart_class->member_del(smart_obj, obj); | ||
190 | |||
191 | o = (Evas_Object_Smart *)(obj->smart.parent->object_data); | ||
192 | o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(obj)); | ||
193 | obj->smart.parent = NULL; | ||
194 | evas_object_smart_member_cache_invalidate(obj, EINA_TRUE, EINA_TRUE); | ||
195 | obj->layer->usage--; | ||
196 | obj->cur.layer = obj->layer->layer; | ||
197 | evas_object_inject(obj, obj->layer->evas); | ||
198 | obj->restack = 1; | ||
199 | evas_object_change(obj); | ||
200 | evas_object_mapped_clip_across_mark(obj); | ||
201 | } | ||
202 | |||
203 | EAPI Evas_Object * | ||
204 | evas_object_smart_parent_get(const Evas_Object *obj) | ||
205 | { | ||
206 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
207 | return NULL; | ||
208 | MAGIC_CHECK_END(); | ||
209 | |||
210 | return obj->smart.parent; | ||
211 | } | ||
212 | |||
213 | EAPI Eina_Bool | ||
214 | evas_object_smart_type_check(const Evas_Object *obj, const char *type) | ||
215 | { | ||
216 | const Evas_Smart_Class *sc; | ||
217 | |||
218 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
219 | return EINA_FALSE; | ||
220 | MAGIC_CHECK_END(); | ||
221 | |||
222 | if (!obj->smart.smart) | ||
223 | return EINA_FALSE; | ||
224 | sc = obj->smart.smart->smart_class; | ||
225 | while (sc) | ||
226 | { | ||
227 | if (!strcmp(sc->name, type)) | ||
228 | return EINA_TRUE; | ||
229 | sc = sc->parent; | ||
230 | } | ||
231 | |||
232 | return EINA_FALSE; | ||
233 | } | ||
234 | |||
235 | EAPI Eina_Bool | ||
236 | evas_object_smart_type_check_ptr(const Evas_Object *obj, const char *type) | ||
237 | { | ||
238 | const Evas_Smart_Class *sc; | ||
239 | |||
240 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
241 | return EINA_FALSE; | ||
242 | MAGIC_CHECK_END(); | ||
243 | |||
244 | if (!obj->smart.smart) | ||
245 | return EINA_FALSE; | ||
246 | sc = obj->smart.smart->smart_class; | ||
247 | while (sc) | ||
248 | { | ||
249 | if (sc->name == type) | ||
250 | return EINA_TRUE; | ||
251 | sc = sc->parent; | ||
252 | } | ||
253 | |||
254 | return EINA_FALSE; | ||
255 | } | ||
256 | |||
257 | EAPI Eina_List * | ||
258 | evas_object_smart_members_get(const Evas_Object *obj) | ||
259 | { | ||
260 | Evas_Object_Smart *o; | ||
261 | Eina_List *members; | ||
262 | Eina_Inlist *member; | ||
263 | |||
264 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
265 | return NULL; | ||
266 | MAGIC_CHECK_END(); | ||
267 | o = (Evas_Object_Smart *)(obj->object_data); | ||
268 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
269 | return NULL; | ||
270 | MAGIC_CHECK_END(); | ||
271 | |||
272 | members = NULL; | ||
273 | for (member = o->contained; member; member = member->next) | ||
274 | members = eina_list_append(members, member); | ||
275 | |||
276 | return members; | ||
277 | } | ||
278 | |||
279 | const Eina_Inlist * | ||
280 | evas_object_smart_members_get_direct(const Evas_Object *obj) | ||
281 | { | ||
282 | Evas_Object_Smart *o; | ||
283 | |||
284 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
285 | return NULL; | ||
286 | MAGIC_CHECK_END(); | ||
287 | o = (Evas_Object_Smart *)(obj->object_data); | ||
288 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
289 | return NULL; | ||
290 | MAGIC_CHECK_END(); | ||
291 | return o->contained; | ||
292 | } | ||
293 | |||
294 | void | ||
295 | _evas_object_smart_members_all_del(Evas_Object *obj) | ||
296 | { | ||
297 | Evas_Object_Smart *o = (Evas_Object_Smart *)(obj->object_data); | ||
298 | while (o->contained) | ||
299 | evas_object_del((Evas_Object *)(o->contained)); | ||
300 | } | ||
301 | |||
302 | EAPI Evas_Object * | ||
303 | evas_object_smart_add(Evas *e, Evas_Smart *s) | ||
304 | { | ||
305 | Evas_Object *obj; | ||
306 | |||
307 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
308 | return NULL; | ||
309 | MAGIC_CHECK_END(); | ||
310 | MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); | ||
311 | return NULL; | ||
312 | MAGIC_CHECK_END(); | ||
313 | |||
314 | obj = evas_object_new(e); | ||
315 | if (!obj) return NULL; | ||
316 | obj->smart.smart = s; | ||
317 | obj->type = s->smart_class->name; | ||
318 | evas_object_smart_init(obj); | ||
319 | evas_object_inject(obj, e); | ||
320 | |||
321 | evas_object_smart_use(s); | ||
322 | |||
323 | if (s->smart_class->add) s->smart_class->add(obj); | ||
324 | |||
325 | return obj; | ||
326 | } | ||
327 | |||
328 | static int | ||
329 | _callback_priority_cmp(const void *_a, const void *_b) | ||
330 | { | ||
331 | const Evas_Smart_Callback *a, *b; | ||
332 | a = (const Evas_Smart_Callback *) _a; | ||
333 | b = (const Evas_Smart_Callback *) _b; | ||
334 | if (a->priority < b->priority) | ||
335 | return -1; | ||
336 | else | ||
337 | return 1; | ||
338 | } | ||
339 | |||
340 | EAPI void | ||
341 | evas_object_smart_callback_add(Evas_Object *obj, const char *event, Evas_Smart_Cb func, const void *data) | ||
342 | { | ||
343 | evas_object_smart_callback_priority_add(obj, event, | ||
344 | EVAS_CALLBACK_PRIORITY_DEFAULT, func, data); | ||
345 | } | ||
346 | |||
347 | EAPI void | ||
348 | evas_object_smart_callback_priority_add(Evas_Object *obj, const char *event, Evas_Callback_Priority priority, Evas_Smart_Cb func, const void *data) | ||
349 | { | ||
350 | Evas_Object_Smart *o; | ||
351 | Evas_Smart_Callback *cb; | ||
352 | |||
353 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
354 | return; | ||
355 | MAGIC_CHECK_END(); | ||
356 | o = (Evas_Object_Smart *)(obj->object_data); | ||
357 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
358 | return; | ||
359 | MAGIC_CHECK_END(); | ||
360 | if (!event) return; | ||
361 | if (!func) return; | ||
362 | EVAS_MEMPOOL_INIT(_mp_cb, "evas_smart_callback", Evas_Smart_Callback, 512, ); | ||
363 | cb = EVAS_MEMPOOL_ALLOC(_mp_cb, Evas_Smart_Callback); | ||
364 | if (!cb) return; | ||
365 | EVAS_MEMPOOL_PREP(_mp_cb, cb, Evas_Smart_Callback); | ||
366 | cb->event = eina_stringshare_add(event); | ||
367 | cb->func = func; | ||
368 | cb->func_data = (void *)data; | ||
369 | cb->priority = priority; | ||
370 | o->callbacks = eina_list_sorted_insert(o->callbacks, _callback_priority_cmp, | ||
371 | cb); | ||
372 | } | ||
373 | |||
374 | EAPI void * | ||
375 | evas_object_smart_callback_del(Evas_Object *obj, const char *event, Evas_Smart_Cb func) | ||
376 | { | ||
377 | Evas_Object_Smart *o; | ||
378 | Eina_List *l; | ||
379 | Evas_Smart_Callback *cb; | ||
380 | |||
381 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
382 | return NULL; | ||
383 | MAGIC_CHECK_END(); | ||
384 | o = (Evas_Object_Smart *)(obj->object_data); | ||
385 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
386 | return NULL; | ||
387 | MAGIC_CHECK_END(); | ||
388 | if (!event) return NULL; | ||
389 | EINA_LIST_FOREACH(o->callbacks, l, cb) | ||
390 | { | ||
391 | if ((!strcmp(cb->event, event)) && (cb->func == func)) | ||
392 | { | ||
393 | void *data; | ||
394 | |||
395 | data = cb->func_data; | ||
396 | cb->delete_me = 1; | ||
397 | o->deletions_waiting = 1; | ||
398 | evas_object_smart_callbacks_clear(obj); | ||
399 | return data; | ||
400 | } | ||
401 | } | ||
402 | return NULL; | ||
403 | } | ||
404 | |||
405 | EAPI void | ||
406 | evas_object_smart_callback_call(Evas_Object *obj, const char *event, void *event_info) | ||
407 | { | ||
408 | Evas_Object_Smart *o; | ||
409 | Eina_List *l; | ||
410 | Evas_Smart_Callback *cb; | ||
411 | const char *strshare; | ||
412 | |||
413 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
414 | return; | ||
415 | MAGIC_CHECK_END(); | ||
416 | o = (Evas_Object_Smart *)(obj->object_data); | ||
417 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
418 | return; | ||
419 | MAGIC_CHECK_END(); | ||
420 | if (!event) return; | ||
421 | if (obj->delete_me) return; | ||
422 | o->walking_list++; | ||
423 | strshare = eina_stringshare_add(event); | ||
424 | EINA_LIST_FOREACH(o->callbacks, l, cb) | ||
425 | { | ||
426 | if (!cb->delete_me) | ||
427 | { | ||
428 | if (cb->event == strshare) | ||
429 | cb->func(cb->func_data, obj, event_info); | ||
430 | } | ||
431 | if (obj->delete_me) | ||
432 | break; | ||
433 | } | ||
434 | eina_stringshare_del(strshare); | ||
435 | o->walking_list--; | ||
436 | evas_object_smart_callbacks_clear(obj); | ||
437 | } | ||
438 | |||
439 | EAPI Eina_Bool | ||
440 | evas_object_smart_callbacks_descriptions_set(Evas_Object *obj, const Evas_Smart_Cb_Description *descriptions) | ||
441 | { | ||
442 | const Evas_Smart_Cb_Description *d; | ||
443 | Evas_Object_Smart *o; | ||
444 | unsigned int i, count = 0; | ||
445 | |||
446 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
447 | return EINA_FALSE; | ||
448 | MAGIC_CHECK_END(); | ||
449 | o = (Evas_Object_Smart *)(obj->object_data); | ||
450 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
451 | return EINA_FALSE; | ||
452 | MAGIC_CHECK_END(); | ||
453 | |||
454 | if ((!descriptions) || (!descriptions->name)) | ||
455 | { | ||
456 | evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0); | ||
457 | return EINA_TRUE; | ||
458 | } | ||
459 | |||
460 | for (count = 0, d = descriptions; d->name; d++) | ||
461 | count++; | ||
462 | |||
463 | evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, count); | ||
464 | if (count == 0) return EINA_TRUE; | ||
465 | |||
466 | for (i = 0, d = descriptions; i < count; d++, i++) | ||
467 | o->callbacks_descriptions.array[i] = d; | ||
468 | |||
469 | evas_smart_cb_descriptions_fix(&o->callbacks_descriptions); | ||
470 | |||
471 | return EINA_TRUE; | ||
472 | } | ||
473 | |||
474 | EAPI void | ||
475 | evas_object_smart_callbacks_descriptions_get(const Evas_Object *obj, const Evas_Smart_Cb_Description ***class_descriptions, unsigned int *class_count, const Evas_Smart_Cb_Description ***instance_descriptions, unsigned int *instance_count) | ||
476 | { | ||
477 | Evas_Object_Smart *o; | ||
478 | |||
479 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
480 | if (class_descriptions) *class_descriptions = NULL; | ||
481 | if (class_count) *class_count = 0; | ||
482 | if (instance_descriptions) *instance_descriptions = NULL; | ||
483 | if (instance_count) *instance_count = 0; | ||
484 | return; | ||
485 | MAGIC_CHECK_END(); | ||
486 | o = (Evas_Object_Smart *)(obj->object_data); | ||
487 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
488 | if (class_descriptions) *class_descriptions = NULL; | ||
489 | if (class_count) *class_count = 0; | ||
490 | if (instance_descriptions) *instance_descriptions = NULL; | ||
491 | if (instance_count) *instance_count = 0; | ||
492 | return; | ||
493 | MAGIC_CHECK_END(); | ||
494 | |||
495 | if (class_descriptions) | ||
496 | *class_descriptions = obj->smart.smart->callbacks.array; | ||
497 | if (class_count) | ||
498 | *class_count = obj->smart.smart->callbacks.size; | ||
499 | |||
500 | if (instance_descriptions) | ||
501 | *instance_descriptions = o->callbacks_descriptions.array; | ||
502 | if (instance_count) | ||
503 | *instance_count = o->callbacks_descriptions.size; | ||
504 | } | ||
505 | |||
506 | EAPI void | ||
507 | evas_object_smart_callback_description_find(const Evas_Object *obj, const char *name, const Evas_Smart_Cb_Description **class_description, const Evas_Smart_Cb_Description **instance_description) | ||
508 | { | ||
509 | Evas_Object_Smart *o; | ||
510 | |||
511 | if (!name) | ||
512 | { | ||
513 | if (class_description) *class_description = NULL; | ||
514 | if (instance_description) *instance_description = NULL; | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
519 | if (class_description) *class_description = NULL; | ||
520 | if (instance_description) *instance_description = NULL; | ||
521 | return; | ||
522 | MAGIC_CHECK_END(); | ||
523 | o = (Evas_Object_Smart *)(obj->object_data); | ||
524 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
525 | if (class_description) *class_description = NULL; | ||
526 | if (instance_description) *instance_description = NULL; | ||
527 | return; | ||
528 | MAGIC_CHECK_END(); | ||
529 | |||
530 | if (class_description) | ||
531 | *class_description = evas_smart_cb_description_find | ||
532 | (&obj->smart.smart->callbacks, name); | ||
533 | |||
534 | if (instance_description) | ||
535 | *instance_description = evas_smart_cb_description_find | ||
536 | (&o->callbacks_descriptions, name); | ||
537 | } | ||
538 | |||
539 | EAPI void | ||
540 | evas_object_smart_need_recalculate_set(Evas_Object *obj, Eina_Bool value) | ||
541 | { | ||
542 | Evas_Object_Smart *o; | ||
543 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
544 | return; | ||
545 | MAGIC_CHECK_END(); | ||
546 | o = obj->object_data; | ||
547 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
548 | return; | ||
549 | MAGIC_CHECK_END(); | ||
550 | |||
551 | // XXX: do i need this? | ||
552 | if (obj->delete_me) return; | ||
553 | |||
554 | /* remove this entry from calc_list or processed list */ | ||
555 | if (eina_clist_element_is_linked(&obj->calc_entry)) | ||
556 | eina_clist_remove(&obj->calc_entry); | ||
557 | |||
558 | value = !!value; | ||
559 | if (value) | ||
560 | eina_clist_add_tail(&obj->layer->evas->calc_list, &obj->calc_entry); | ||
561 | else | ||
562 | eina_clist_add_tail(&obj->layer->evas->calc_done, &obj->calc_entry); | ||
563 | |||
564 | if (o->need_recalculate == value) return; | ||
565 | |||
566 | if (obj->recalculate_cycle > 254) | ||
567 | { | ||
568 | ERR("Object %p is not stable during recalc loop", obj); | ||
569 | return; | ||
570 | } | ||
571 | if (obj->layer->evas->in_smart_calc) obj->recalculate_cycle++; | ||
572 | o->need_recalculate = value; | ||
573 | } | ||
574 | |||
575 | EAPI Eina_Bool | ||
576 | evas_object_smart_need_recalculate_get(const Evas_Object *obj) | ||
577 | { | ||
578 | Evas_Object_Smart *o; | ||
579 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
580 | return EINA_FALSE; | ||
581 | MAGIC_CHECK_END(); | ||
582 | o = obj->object_data; | ||
583 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
584 | return EINA_FALSE; | ||
585 | MAGIC_CHECK_END(); | ||
586 | |||
587 | return o->need_recalculate; | ||
588 | } | ||
589 | |||
590 | EAPI void | ||
591 | evas_object_smart_calculate(Evas_Object *obj) | ||
592 | { | ||
593 | Evas_Object_Smart *o; | ||
594 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
595 | return; | ||
596 | MAGIC_CHECK_END(); | ||
597 | o = obj->object_data; | ||
598 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
599 | return; | ||
600 | MAGIC_CHECK_END(); | ||
601 | |||
602 | if (!obj->smart.smart->smart_class->calculate) | ||
603 | return; | ||
604 | |||
605 | o->need_recalculate = 0; | ||
606 | obj->smart.smart->smart_class->calculate(obj); | ||
607 | } | ||
608 | |||
609 | EAPI void | ||
610 | evas_smart_objects_calculate(Evas *e) | ||
611 | { | ||
612 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
613 | return; | ||
614 | MAGIC_CHECK_END(); | ||
615 | evas_call_smarts_calculate(e); | ||
616 | } | ||
617 | |||
618 | EAPI int | ||
619 | evas_smart_objects_calculate_count_get(const Evas *e) | ||
620 | { | ||
621 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
622 | return 0; | ||
623 | MAGIC_CHECK_END(); | ||
624 | return e->smart_calc_count; | ||
625 | } | ||
626 | |||
627 | /** | ||
628 | * Call calculate() on all smart objects that need_recalculate. | ||
629 | * | ||
630 | * @internal | ||
631 | */ | ||
632 | void | ||
633 | evas_call_smarts_calculate(Evas *e) | ||
634 | { | ||
635 | Eina_Clist *elem; | ||
636 | Evas_Object *obj; | ||
637 | |||
638 | // printf("+CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALC-----------v\n"); | ||
639 | evas_event_freeze(e); | ||
640 | e->in_smart_calc++; | ||
641 | |||
642 | while (NULL != (elem = eina_clist_head(&e->calc_list))) | ||
643 | { | ||
644 | Evas_Object_Smart *o; | ||
645 | |||
646 | /* move the item to the processed list */ | ||
647 | obj = EINA_CLIST_ENTRY(elem, Evas_Object, calc_entry); | ||
648 | eina_clist_remove(&obj->calc_entry); | ||
649 | if (obj->delete_me) continue; | ||
650 | eina_clist_add_tail(&e->calc_done, &obj->calc_entry); | ||
651 | |||
652 | o = obj->object_data; | ||
653 | |||
654 | if (o->need_recalculate) | ||
655 | { | ||
656 | o->need_recalculate = 0; | ||
657 | obj->smart.smart->smart_class->calculate(obj); | ||
658 | } | ||
659 | } | ||
660 | |||
661 | while (NULL != (elem = eina_clist_head(&e->calc_done))) | ||
662 | { | ||
663 | obj = EINA_CLIST_ENTRY(elem, Evas_Object, calc_entry); | ||
664 | obj->recalculate_cycle = 0; | ||
665 | eina_clist_remove(&obj->calc_entry); | ||
666 | } | ||
667 | |||
668 | e->in_smart_calc--; | ||
669 | if (e->in_smart_calc == 0) e->smart_calc_count++; | ||
670 | evas_event_thaw(e); | ||
671 | evas_event_thaw_eval(e); | ||
672 | } | ||
673 | |||
674 | EAPI void | ||
675 | evas_object_smart_changed(Evas_Object *obj) | ||
676 | { | ||
677 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
678 | return; | ||
679 | MAGIC_CHECK_END(); | ||
680 | evas_object_change(obj); | ||
681 | evas_object_smart_need_recalculate_set(obj, 1); | ||
682 | } | ||
683 | |||
684 | /* internal calls */ | ||
685 | static void | ||
686 | evas_object_smart_callbacks_clear(Evas_Object *obj) | ||
687 | { | ||
688 | Evas_Object_Smart *o; | ||
689 | Eina_List *l; | ||
690 | Evas_Smart_Callback *cb; | ||
691 | |||
692 | o = (Evas_Object_Smart *)(obj->object_data); | ||
693 | |||
694 | if (o->walking_list) return; | ||
695 | if (!o->deletions_waiting) return; | ||
696 | for (l = o->callbacks; l;) | ||
697 | { | ||
698 | cb = eina_list_data_get(l); | ||
699 | l = eina_list_next(l); | ||
700 | if (cb->delete_me) | ||
701 | { | ||
702 | o->callbacks = eina_list_remove(o->callbacks, cb); | ||
703 | if (cb->event) eina_stringshare_del(cb->event); | ||
704 | EVAS_MEMPOOL_FREE(_mp_cb, cb); | ||
705 | } | ||
706 | } | ||
707 | } | ||
708 | |||
709 | void | ||
710 | evas_object_smart_del(Evas_Object *obj) | ||
711 | { | ||
712 | Evas_Smart *s; | ||
713 | |||
714 | if (obj->delete_me) return; | ||
715 | s = obj->smart.smart; | ||
716 | if ((s) && (s->smart_class->del)) s->smart_class->del(obj); | ||
717 | if (obj->smart.parent) evas_object_smart_member_del(obj); | ||
718 | if (s) evas_object_smart_unuse(s); | ||
719 | } | ||
720 | |||
721 | void | ||
722 | evas_object_smart_cleanup(Evas_Object *obj) | ||
723 | { | ||
724 | Evas_Object_Smart *o; | ||
725 | |||
726 | if (obj->smart.parent) | ||
727 | evas_object_smart_member_del(obj); | ||
728 | |||
729 | o = (Evas_Object_Smart *)(obj->object_data); | ||
730 | if (o->magic == MAGIC_OBJ_SMART) | ||
731 | { | ||
732 | if (obj->calc_entry.next) | ||
733 | eina_clist_remove(&obj->calc_entry); | ||
734 | |||
735 | while (o->contained) | ||
736 | evas_object_smart_member_del((Evas_Object *)o->contained); | ||
737 | |||
738 | while (o->callbacks) | ||
739 | { | ||
740 | Evas_Smart_Callback *cb = o->callbacks->data; | ||
741 | o->callbacks = eina_list_remove(o->callbacks, cb); | ||
742 | if (cb->event) eina_stringshare_del(cb->event); | ||
743 | EVAS_MEMPOOL_FREE(_mp_cb, cb); | ||
744 | } | ||
745 | |||
746 | evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0); | ||
747 | o->data = NULL; | ||
748 | } | ||
749 | |||
750 | obj->smart.parent = NULL; | ||
751 | obj->smart.smart = NULL; | ||
752 | } | ||
753 | |||
754 | void | ||
755 | evas_object_smart_member_cache_invalidate(Evas_Object *obj, | ||
756 | Eina_Bool pass_events, | ||
757 | Eina_Bool freeze_events) | ||
758 | { | ||
759 | Evas_Object_Smart *o; | ||
760 | Evas_Object *member; | ||
761 | |||
762 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
763 | return; | ||
764 | MAGIC_CHECK_END(); | ||
765 | |||
766 | if (pass_events) | ||
767 | obj->parent_cache.pass_events_valid = EINA_FALSE; | ||
768 | if (freeze_events) | ||
769 | obj->parent_cache.freeze_events_valid = EINA_FALSE; | ||
770 | |||
771 | o = obj->object_data; | ||
772 | if (o->magic != MAGIC_OBJ_SMART) return; | ||
773 | |||
774 | EINA_INLIST_FOREACH(o->contained, member) | ||
775 | evas_object_smart_member_cache_invalidate(member, | ||
776 | pass_events, | ||
777 | freeze_events); | ||
778 | } | ||
779 | |||
780 | void | ||
781 | evas_object_smart_member_raise(Evas_Object *member) | ||
782 | { | ||
783 | Evas_Object_Smart *o; | ||
784 | |||
785 | o = (Evas_Object_Smart *)(member->smart.parent->object_data); | ||
786 | o->contained = eina_inlist_demote(o->contained, EINA_INLIST_GET(member)); | ||
787 | } | ||
788 | |||
789 | void | ||
790 | evas_object_smart_member_lower(Evas_Object *member) | ||
791 | { | ||
792 | Evas_Object_Smart *o; | ||
793 | |||
794 | o = (Evas_Object_Smart *)(member->smart.parent->object_data); | ||
795 | o->contained = eina_inlist_promote(o->contained, EINA_INLIST_GET(member)); | ||
796 | } | ||
797 | |||
798 | void | ||
799 | evas_object_smart_member_stack_above(Evas_Object *member, Evas_Object *other) | ||
800 | { | ||
801 | Evas_Object_Smart *o; | ||
802 | |||
803 | o = (Evas_Object_Smart *)(member->smart.parent->object_data); | ||
804 | o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(member)); | ||
805 | o->contained = eina_inlist_append_relative(o->contained, EINA_INLIST_GET(member), EINA_INLIST_GET(other)); | ||
806 | } | ||
807 | |||
808 | void | ||
809 | evas_object_smart_member_stack_below(Evas_Object *member, Evas_Object *other) | ||
810 | { | ||
811 | Evas_Object_Smart *o; | ||
812 | |||
813 | o = (Evas_Object_Smart *)(member->smart.parent->object_data); | ||
814 | o->contained = eina_inlist_remove(o->contained, EINA_INLIST_GET(member)); | ||
815 | o->contained = eina_inlist_prepend_relative(o->contained, EINA_INLIST_GET(member), EINA_INLIST_GET(other)); | ||
816 | } | ||
817 | |||
818 | /* all nice and private */ | ||
819 | static void | ||
820 | evas_object_smart_init(Evas_Object *obj) | ||
821 | { | ||
822 | /* alloc smart obj, setup methods and default values */ | ||
823 | obj->object_data = evas_object_smart_new(); | ||
824 | /* set up default settings for this kind of object */ | ||
825 | obj->cur.color.r = 255; | ||
826 | obj->cur.color.g = 255; | ||
827 | obj->cur.color.b = 255; | ||
828 | obj->cur.color.a = 255; | ||
829 | obj->cur.geometry.x = 0; | ||
830 | obj->cur.geometry.y = 0; | ||
831 | obj->cur.geometry.w = 0; | ||
832 | obj->cur.geometry.h = 0; | ||
833 | obj->cur.layer = 0; | ||
834 | /* set up object-specific settings */ | ||
835 | obj->prev = obj->cur; | ||
836 | /* set up methods (compulsory) */ | ||
837 | obj->func = &object_func; | ||
838 | } | ||
839 | |||
840 | static void * | ||
841 | evas_object_smart_new(void) | ||
842 | { | ||
843 | Evas_Object_Smart *o; | ||
844 | |||
845 | /* alloc obj private data */ | ||
846 | EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_smart", Evas_Object_Smart, 256, NULL); | ||
847 | o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Smart); | ||
848 | if (!o) return NULL; | ||
849 | EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Smart); | ||
850 | o->magic = MAGIC_OBJ_SMART; | ||
851 | return o; | ||
852 | } | ||
853 | |||
854 | static void | ||
855 | evas_object_smart_free(Evas_Object *obj) | ||
856 | { | ||
857 | Evas_Object_Smart *o; | ||
858 | |||
859 | /* frees private object data. very simple here */ | ||
860 | o = (Evas_Object_Smart *)(obj->object_data); | ||
861 | MAGIC_CHECK(o, Evas_Object_Smart, MAGIC_OBJ_SMART); | ||
862 | return; | ||
863 | MAGIC_CHECK_END(); | ||
864 | /* free obj */ | ||
865 | o->magic = 0; | ||
866 | EVAS_MEMPOOL_FREE(_mp_obj, o); | ||
867 | } | ||
868 | |||
869 | static void | ||
870 | evas_object_smart_render(Evas_Object *obj __UNUSED__, void *output __UNUSED__, void *context __UNUSED__, void *surface __UNUSED__, int x __UNUSED__, int y __UNUSED__) | ||
871 | { | ||
872 | return; | ||
873 | } | ||
874 | |||
875 | static void | ||
876 | evas_object_smart_render_pre(Evas_Object *obj) | ||
877 | { | ||
878 | if (obj->pre_render_done) return; | ||
879 | if ((obj->cur.map != obj->prev.map) || | ||
880 | (obj->cur.usemap != obj->prev.usemap)) | ||
881 | { | ||
882 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
883 | goto done; | ||
884 | } | ||
885 | done: | ||
886 | obj->pre_render_done = 1; | ||
887 | } | ||
888 | |||
889 | static void | ||
890 | evas_object_smart_render_post(Evas_Object *obj) | ||
891 | { | ||
892 | obj->prev = obj->cur; | ||
893 | } | ||
894 | |||
895 | static unsigned int evas_object_smart_id_get(Evas_Object *obj) | ||
896 | { | ||
897 | Evas_Object_Smart *o; | ||
898 | |||
899 | o = (Evas_Object_Smart *)(obj->object_data); | ||
900 | if (!o) return 0; | ||
901 | return MAGIC_OBJ_SMART; | ||
902 | } | ||
903 | |||
904 | static unsigned int evas_object_smart_visual_id_get(Evas_Object *obj) | ||
905 | { | ||
906 | Evas_Object_Smart *o; | ||
907 | |||
908 | o = (Evas_Object_Smart *)(obj->object_data); | ||
909 | if (!o) return 0; | ||
910 | return MAGIC_OBJ_CONTAINER; | ||
911 | } | ||
912 | |||
913 | static void *evas_object_smart_engine_data_get(Evas_Object *obj) | ||
914 | { | ||
915 | Evas_Object_Smart *o; | ||
916 | |||
917 | o = (Evas_Object_Smart *)(obj->object_data); | ||
918 | if (!o) return NULL; | ||
919 | return o->engine_data; | ||
920 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_smart_clipped.c b/libraries/evas/src/lib/canvas/evas_object_smart_clipped.c new file mode 100644 index 0000000..9b9fa6d --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_smart_clipped.c | |||
@@ -0,0 +1,183 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | #define CSO_DATA_GET_OR_RETURN(obj, ptr) \ | ||
5 | Evas_Object_Smart_Clipped_Data *ptr = evas_object_smart_data_get(obj); \ | ||
6 | if (!ptr) return; | ||
7 | |||
8 | EAPI void | ||
9 | evas_object_smart_move_children_relative(Evas_Object *obj, Evas_Coord dx, Evas_Coord dy) | ||
10 | { | ||
11 | const Eina_Inlist *lst; | ||
12 | Evas_Object *child; | ||
13 | |||
14 | if ((dx == 0) && (dy == 0)) | ||
15 | return; | ||
16 | |||
17 | lst = evas_object_smart_members_get_direct(obj); | ||
18 | EINA_INLIST_FOREACH(lst, child) | ||
19 | { | ||
20 | Evas_Coord orig_x, orig_y; | ||
21 | |||
22 | // shortcut as we are in evas | ||
23 | // evas_object_geometry_get(child, &orig_x, &orig_y, NULL, NULL); | ||
24 | if (child->delete_me) continue; | ||
25 | if (child->is_static_clip) continue; | ||
26 | orig_x = child->cur.geometry.x; | ||
27 | orig_y = child->cur.geometry.y; | ||
28 | evas_object_move(child, orig_x + dx, orig_y + dy); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | EAPI Evas_Object * | ||
33 | evas_object_smart_clipped_clipper_get(Evas_Object *obj) | ||
34 | { | ||
35 | Evas_Object_Smart_Clipped_Data *cso = evas_object_smart_data_get(obj); | ||
36 | if (!cso) | ||
37 | return NULL; | ||
38 | |||
39 | return cso->clipper; | ||
40 | } | ||
41 | |||
42 | static void | ||
43 | evas_object_smart_clipped_smart_add(Evas_Object *obj) | ||
44 | { | ||
45 | Evas_Object_Smart_Clipped_Data *cso; | ||
46 | Evas_Object *clipper; | ||
47 | |||
48 | cso = evas_object_smart_data_get(obj); | ||
49 | if (!cso) | ||
50 | cso = calloc(1, sizeof(*cso)); /* users can provide it or realloc() later */ | ||
51 | |||
52 | cso->evas = evas_object_evas_get(obj); | ||
53 | clipper = evas_object_rectangle_add(cso->evas); | ||
54 | evas_object_static_clip_set(clipper, 1); | ||
55 | cso->clipper = NULL; | ||
56 | evas_object_smart_member_add(clipper, obj); | ||
57 | cso->clipper = clipper; | ||
58 | evas_object_color_set(cso->clipper, 255, 255, 255, 255); | ||
59 | evas_object_move(cso->clipper, -100000, -100000); | ||
60 | evas_object_resize(cso->clipper, 200000, 200000); | ||
61 | evas_object_pass_events_set(cso->clipper, 1); | ||
62 | evas_object_hide(cso->clipper); /* show when have something clipped to it */ | ||
63 | |||
64 | evas_object_smart_data_set(obj, cso); | ||
65 | } | ||
66 | |||
67 | static void | ||
68 | evas_object_smart_clipped_smart_del(Evas_Object *obj) | ||
69 | { | ||
70 | CSO_DATA_GET_OR_RETURN(obj, cso); | ||
71 | |||
72 | if (cso->clipper) | ||
73 | { | ||
74 | Evas_Object *clipper = cso->clipper; | ||
75 | cso->clipper = NULL; | ||
76 | evas_object_del(clipper); | ||
77 | } | ||
78 | |||
79 | _evas_object_smart_members_all_del(obj); | ||
80 | |||
81 | free(cso); | ||
82 | evas_object_smart_data_set(obj, NULL); | ||
83 | } | ||
84 | |||
85 | static void | ||
86 | evas_object_smart_clipped_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
87 | { | ||
88 | Evas_Coord orig_x, orig_y; | ||
89 | |||
90 | evas_object_geometry_get(obj, &orig_x, &orig_y, NULL, NULL); | ||
91 | evas_object_smart_move_children_relative(obj, x - orig_x, y - orig_y); | ||
92 | } | ||
93 | |||
94 | static void | ||
95 | evas_object_smart_clipped_smart_show(Evas_Object *obj) | ||
96 | { | ||
97 | CSO_DATA_GET_OR_RETURN(obj, cso); | ||
98 | if (evas_object_clipees_get(cso->clipper)) | ||
99 | evas_object_show(cso->clipper); /* just show if clipper being used */ | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | evas_object_smart_clipped_smart_hide(Evas_Object *obj) | ||
104 | { | ||
105 | CSO_DATA_GET_OR_RETURN(obj, cso); | ||
106 | evas_object_hide(cso->clipper); | ||
107 | } | ||
108 | |||
109 | static void | ||
110 | evas_object_smart_clipped_smart_color_set(Evas_Object *obj, int r, int g, int b, int a) | ||
111 | { | ||
112 | CSO_DATA_GET_OR_RETURN(obj, cso); | ||
113 | evas_object_color_set(cso->clipper, r, g, b, a); | ||
114 | } | ||
115 | |||
116 | static void | ||
117 | evas_object_smart_clipped_smart_clip_set(Evas_Object *obj, Evas_Object *clip) | ||
118 | { | ||
119 | CSO_DATA_GET_OR_RETURN(obj, cso); | ||
120 | evas_object_clip_set(cso->clipper, clip); | ||
121 | } | ||
122 | |||
123 | static void | ||
124 | evas_object_smart_clipped_smart_clip_unset(Evas_Object *obj) | ||
125 | { | ||
126 | CSO_DATA_GET_OR_RETURN(obj, cso); | ||
127 | evas_object_clip_unset(cso->clipper); | ||
128 | } | ||
129 | |||
130 | static void | ||
131 | evas_object_smart_clipped_smart_member_add(Evas_Object *obj, Evas_Object *member) | ||
132 | { | ||
133 | CSO_DATA_GET_OR_RETURN(obj, cso); | ||
134 | if (!cso->clipper) | ||
135 | return; | ||
136 | evas_object_clip_set(member, cso->clipper); | ||
137 | if (evas_object_visible_get(obj)) | ||
138 | evas_object_show(cso->clipper); | ||
139 | } | ||
140 | |||
141 | static void | ||
142 | evas_object_smart_clipped_smart_member_del(Evas_Object *obj, Evas_Object *member) | ||
143 | { | ||
144 | CSO_DATA_GET_OR_RETURN(obj, cso); | ||
145 | if (!cso->clipper) | ||
146 | return; | ||
147 | evas_object_clip_unset(member); | ||
148 | if (!evas_object_clipees_get(cso->clipper)) | ||
149 | evas_object_hide(cso->clipper); | ||
150 | } | ||
151 | |||
152 | EAPI void | ||
153 | evas_object_smart_clipped_smart_set(Evas_Smart_Class *sc) | ||
154 | { | ||
155 | if (!sc) | ||
156 | return; | ||
157 | |||
158 | sc->add = evas_object_smart_clipped_smart_add; | ||
159 | sc->del = evas_object_smart_clipped_smart_del; | ||
160 | sc->move = evas_object_smart_clipped_smart_move; | ||
161 | sc->show = evas_object_smart_clipped_smart_show; | ||
162 | sc->hide = evas_object_smart_clipped_smart_hide; | ||
163 | sc->color_set = evas_object_smart_clipped_smart_color_set; | ||
164 | sc->clip_set = evas_object_smart_clipped_smart_clip_set; | ||
165 | sc->clip_unset = evas_object_smart_clipped_smart_clip_unset; | ||
166 | sc->calculate = NULL; | ||
167 | sc->member_add = evas_object_smart_clipped_smart_member_add; | ||
168 | sc->member_del = evas_object_smart_clipped_smart_member_del; | ||
169 | } | ||
170 | |||
171 | EAPI const Evas_Smart_Class * | ||
172 | evas_object_smart_clipped_class_get(void) | ||
173 | { | ||
174 | static Evas_Smart_Class _sc = EVAS_SMART_CLASS_INIT_NAME_VERSION("EvasObjectSmartClipped"); | ||
175 | static const Evas_Smart_Class *class = NULL; | ||
176 | |||
177 | if (class) | ||
178 | return class; | ||
179 | |||
180 | evas_object_smart_clipped_smart_set(&_sc); | ||
181 | class = &_sc; | ||
182 | return class; | ||
183 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_table.c b/libraries/evas/src/lib/canvas/evas_object_table.c new file mode 100644 index 0000000..6e28fce --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_table.c | |||
@@ -0,0 +1,1373 @@ | |||
1 | #include <errno.h> | ||
2 | #include "evas_common.h" | ||
3 | |||
4 | typedef struct _Evas_Object_Table_Data Evas_Object_Table_Data; | ||
5 | typedef struct _Evas_Object_Table_Option Evas_Object_Table_Option; | ||
6 | typedef struct _Evas_Object_Table_Cache Evas_Object_Table_Cache; | ||
7 | typedef struct _Evas_Object_Table_Iterator Evas_Object_Table_Iterator; | ||
8 | typedef struct _Evas_Object_Table_Accessor Evas_Object_Table_Accessor; | ||
9 | |||
10 | struct _Evas_Object_Table_Option | ||
11 | { | ||
12 | Evas_Object *obj; | ||
13 | unsigned short col, row, colspan, rowspan, end_col, end_row; | ||
14 | struct { | ||
15 | Evas_Coord w, h; | ||
16 | } min, max; | ||
17 | struct { | ||
18 | double h, v; | ||
19 | } align; | ||
20 | struct { | ||
21 | Evas_Coord l, r, t, b; | ||
22 | } pad; | ||
23 | Eina_Bool expand_h : 1; /* XXX required? */ | ||
24 | Eina_Bool expand_v : 1; /* XXX required? */ | ||
25 | Eina_Bool fill_h : 1; | ||
26 | Eina_Bool fill_v : 1; | ||
27 | }; | ||
28 | |||
29 | struct _Evas_Object_Table_Cache | ||
30 | { | ||
31 | struct { | ||
32 | struct { | ||
33 | double h, v; | ||
34 | } weights; | ||
35 | struct { | ||
36 | int h, v; | ||
37 | } expands; | ||
38 | struct { | ||
39 | Evas_Coord w, h; | ||
40 | } min; | ||
41 | } total; | ||
42 | struct { | ||
43 | double *h, *v; | ||
44 | } weights; | ||
45 | struct { | ||
46 | Evas_Coord *h, *v; | ||
47 | } sizes; | ||
48 | struct { | ||
49 | Eina_Bool *h, *v; | ||
50 | } expands; | ||
51 | double ___pad; // padding to make sure doubles at end can be aligned | ||
52 | }; | ||
53 | |||
54 | struct _Evas_Object_Table_Data | ||
55 | { | ||
56 | Evas_Object_Smart_Clipped_Data base; | ||
57 | Eina_List *children; | ||
58 | struct { | ||
59 | Evas_Coord h, v; | ||
60 | } pad; | ||
61 | struct { | ||
62 | double h, v; | ||
63 | } align; | ||
64 | struct { | ||
65 | int cols, rows; | ||
66 | } size; | ||
67 | Evas_Object_Table_Cache *cache; | ||
68 | Evas_Object_Table_Homogeneous_Mode homogeneous; | ||
69 | Eina_Bool hints_changed : 1; | ||
70 | Eina_Bool expand_h : 1; | ||
71 | Eina_Bool expand_v : 1; | ||
72 | Eina_Bool is_mirrored : 1; | ||
73 | }; | ||
74 | |||
75 | struct _Evas_Object_Table_Iterator | ||
76 | { | ||
77 | Eina_Iterator iterator; | ||
78 | |||
79 | Eina_Iterator *real_iterator; | ||
80 | const Evas_Object *table; | ||
81 | }; | ||
82 | |||
83 | struct _Evas_Object_Table_Accessor | ||
84 | { | ||
85 | Eina_Accessor accessor; | ||
86 | |||
87 | Eina_Accessor *real_accessor; | ||
88 | const Evas_Object *table; | ||
89 | }; | ||
90 | |||
91 | #define EVAS_OBJECT_TABLE_DATA_GET(o, ptr) \ | ||
92 | Evas_Object_Table_Data *ptr = evas_object_smart_data_get(o) | ||
93 | |||
94 | #define EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, ptr) \ | ||
95 | EVAS_OBJECT_TABLE_DATA_GET(o, ptr); \ | ||
96 | if (!ptr) \ | ||
97 | { \ | ||
98 | CRIT("no widget data for object %p (%s)", \ | ||
99 | o, evas_object_type_get(o)); \ | ||
100 | abort(); \ | ||
101 | return; \ | ||
102 | } | ||
103 | |||
104 | #define EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, ptr, val) \ | ||
105 | EVAS_OBJECT_TABLE_DATA_GET(o, ptr); \ | ||
106 | if (!ptr) \ | ||
107 | { \ | ||
108 | CRIT("No widget data for object %p (%s)", \ | ||
109 | o, evas_object_type_get(o)); \ | ||
110 | abort(); \ | ||
111 | return val; \ | ||
112 | } | ||
113 | |||
114 | static const char EVAS_OBJECT_TABLE_OPTION_KEY[] = "|EvTb"; | ||
115 | |||
116 | static Eina_Bool | ||
117 | _evas_object_table_iterator_next(Evas_Object_Table_Iterator *it, void **data) | ||
118 | { | ||
119 | Evas_Object_Table_Option *opt; | ||
120 | |||
121 | if (!eina_iterator_next(it->real_iterator, (void **)&opt)) | ||
122 | return EINA_FALSE; | ||
123 | if (data) *data = opt->obj; | ||
124 | return EINA_TRUE; | ||
125 | } | ||
126 | |||
127 | static Evas_Object * | ||
128 | _evas_object_table_iterator_get_container(Evas_Object_Table_Iterator *it) | ||
129 | { | ||
130 | return (Evas_Object *)it->table; | ||
131 | } | ||
132 | |||
133 | static void | ||
134 | _evas_object_table_iterator_free(Evas_Object_Table_Iterator *it) | ||
135 | { | ||
136 | eina_iterator_free(it->real_iterator); | ||
137 | free(it); | ||
138 | } | ||
139 | |||
140 | static Eina_Bool | ||
141 | _evas_object_table_accessor_get_at(Evas_Object_Table_Accessor *it, unsigned int idx, void **data) | ||
142 | { | ||
143 | Evas_Object_Table_Option *opt = NULL; | ||
144 | |||
145 | if (!eina_accessor_data_get(it->real_accessor, idx, (void **)&opt)) | ||
146 | return EINA_FALSE; | ||
147 | if (data) *data = opt->obj; | ||
148 | return EINA_TRUE; | ||
149 | } | ||
150 | |||
151 | static Evas_Object * | ||
152 | _evas_object_table_accessor_get_container(Evas_Object_Table_Accessor *it) | ||
153 | { | ||
154 | return (Evas_Object *)it->table; | ||
155 | } | ||
156 | |||
157 | static void | ||
158 | _evas_object_table_accessor_free(Evas_Object_Table_Accessor *it) | ||
159 | { | ||
160 | eina_accessor_free(it->real_accessor); | ||
161 | free(it); | ||
162 | } | ||
163 | |||
164 | static Evas_Object_Table_Cache * | ||
165 | _evas_object_table_cache_alloc(int cols, int rows) | ||
166 | { | ||
167 | Evas_Object_Table_Cache *cache; | ||
168 | int size; | ||
169 | |||
170 | size = sizeof(Evas_Object_Table_Cache) + | ||
171 | ((cols + rows) * | ||
172 | (sizeof(double) + sizeof(Evas_Coord) + sizeof(Eina_Bool))); | ||
173 | cache = malloc(size); | ||
174 | if (!cache) | ||
175 | { | ||
176 | ERR("Could not allocate table cache %dx%d (%d bytes): %s", | ||
177 | cols, rows, size, strerror(errno)); | ||
178 | return NULL; | ||
179 | } | ||
180 | |||
181 | cache->weights.h = (double *)(cache + 1); | ||
182 | cache->weights.v = (double *)(cache->weights.h + cols); | ||
183 | cache->sizes.h = (Evas_Coord *)(cache->weights.v + rows); | ||
184 | cache->sizes.v = (Evas_Coord *)(cache->sizes.h + cols); | ||
185 | cache->expands.h = (Eina_Bool *)(cache->sizes.v + rows); | ||
186 | cache->expands.v = (Eina_Bool *)(cache->expands.h + cols); | ||
187 | |||
188 | return cache; | ||
189 | } | ||
190 | |||
191 | static void | ||
192 | _evas_object_table_cache_free(Evas_Object_Table_Cache *cache) | ||
193 | { | ||
194 | free(cache); | ||
195 | } | ||
196 | |||
197 | static void | ||
198 | _evas_object_table_cache_reset(Evas_Object_Table_Data *priv) | ||
199 | { | ||
200 | Evas_Object_Table_Cache *c = priv->cache; | ||
201 | int size; | ||
202 | |||
203 | c->total.expands.v = 0; | ||
204 | c->total.expands.h = 0; | ||
205 | c->total.min.w = 0; | ||
206 | c->total.min.h = 0; | ||
207 | |||
208 | size = ((priv->size.rows + priv->size.cols) * | ||
209 | (sizeof(double) + sizeof(Evas_Coord) + sizeof(Eina_Bool))); | ||
210 | memset(c + 1, 0, size); | ||
211 | } | ||
212 | |||
213 | static void | ||
214 | _evas_object_table_cache_invalidate(Evas_Object_Table_Data *priv) | ||
215 | { | ||
216 | priv->hints_changed = 1; | ||
217 | if (priv->cache) | ||
218 | { | ||
219 | _evas_object_table_cache_free(priv->cache); | ||
220 | priv->cache = NULL; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static Evas_Object_Table_Option * | ||
225 | _evas_object_table_option_get(Evas_Object *o) | ||
226 | { | ||
227 | return evas_object_data_get(o, EVAS_OBJECT_TABLE_OPTION_KEY); | ||
228 | } | ||
229 | |||
230 | static void | ||
231 | _evas_object_table_option_set(Evas_Object *o, const Evas_Object_Table_Option *opt) | ||
232 | { | ||
233 | evas_object_data_set(o, EVAS_OBJECT_TABLE_OPTION_KEY, opt); | ||
234 | } | ||
235 | |||
236 | static Evas_Object_Table_Option * | ||
237 | _evas_object_table_option_del(Evas_Object *o) | ||
238 | { | ||
239 | return evas_object_data_del(o, EVAS_OBJECT_TABLE_OPTION_KEY); | ||
240 | } | ||
241 | |||
242 | static void | ||
243 | _on_child_del(void *data, Evas *evas __UNUSED__, Evas_Object *child, void *einfo __UNUSED__) | ||
244 | { | ||
245 | Evas_Object *table = data; | ||
246 | evas_object_table_unpack(table, child); | ||
247 | } | ||
248 | |||
249 | static void | ||
250 | _on_child_hints_changed(void *data, Evas *evas __UNUSED__, Evas_Object *child __UNUSED__, void *einfo __UNUSED__) | ||
251 | { | ||
252 | Evas_Object *table = data; | ||
253 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(table, priv); | ||
254 | _evas_object_table_cache_invalidate(priv); | ||
255 | evas_object_smart_changed(table); | ||
256 | } | ||
257 | |||
258 | static void | ||
259 | _evas_object_table_child_connect(Evas_Object *o, Evas_Object *child) | ||
260 | { | ||
261 | evas_object_event_callback_add | ||
262 | (child, EVAS_CALLBACK_DEL, _on_child_del, o); | ||
263 | evas_object_event_callback_add | ||
264 | (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o); | ||
265 | } | ||
266 | |||
267 | static void | ||
268 | _evas_object_table_child_disconnect(Evas_Object *o, Evas_Object *child) | ||
269 | { | ||
270 | evas_object_event_callback_del_full | ||
271 | (child, EVAS_CALLBACK_DEL, _on_child_del, o); | ||
272 | evas_object_event_callback_del_full | ||
273 | (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o); | ||
274 | } | ||
275 | |||
276 | static void | ||
277 | _evas_object_table_calculate_cell(const Evas_Object_Table_Option *opt, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) | ||
278 | { | ||
279 | Evas_Coord cw, ch; | ||
280 | |||
281 | *w -= opt->pad.l + opt->pad.r; | ||
282 | if (*w < opt->min.w) | ||
283 | cw = opt->min.w; | ||
284 | else if ((opt->max.w > -1) && (*w > opt->max.w)) | ||
285 | cw = opt->max.w; | ||
286 | else if (opt->fill_h) | ||
287 | cw = *w; | ||
288 | else | ||
289 | cw = opt->min.w; | ||
290 | |||
291 | *h -= opt->pad.t + opt->pad.b; | ||
292 | if (*h < opt->min.h) | ||
293 | ch = opt->min.h; | ||
294 | else if ((opt->max.h > -1) && (*h > opt->max.h)) | ||
295 | ch = opt->max.h; | ||
296 | else if (opt->fill_v) | ||
297 | ch = *h; | ||
298 | else | ||
299 | ch = opt->min.h; | ||
300 | |||
301 | *x += opt->pad.l; | ||
302 | if (cw != *w) | ||
303 | { | ||
304 | *x += (*w - cw) * opt->align.h; | ||
305 | *w = cw; | ||
306 | } | ||
307 | |||
308 | *y += opt->pad.t; | ||
309 | if (ch != *h) | ||
310 | { | ||
311 | *y += (*h - ch) * opt->align.v; | ||
312 | *h = ch; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | static void | ||
317 | _evas_object_table_calculate_hints_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv) | ||
318 | { | ||
319 | Eina_List *l; | ||
320 | Evas_Object_Table_Option *opt; | ||
321 | Evas_Coord minw, minh, o_minw, o_minh; | ||
322 | Eina_Bool expand_h, expand_v; | ||
323 | |||
324 | o_minw = 0; | ||
325 | o_minh = 0; | ||
326 | minw = 0; | ||
327 | minh = 0; | ||
328 | expand_h = 0; | ||
329 | expand_v = 0; | ||
330 | |||
331 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
332 | { | ||
333 | Evas_Object *child = opt->obj; | ||
334 | Evas_Coord child_minw, child_minh, cell_minw, cell_minh; | ||
335 | double weightw, weighth; | ||
336 | |||
337 | evas_object_size_hint_min_get(child, &opt->min.w, &opt->min.h); | ||
338 | evas_object_size_hint_max_get(child, &opt->max.w, &opt->max.h); | ||
339 | evas_object_size_hint_padding_get | ||
340 | (child, &opt->pad.l, &opt->pad.r, &opt->pad.t, &opt->pad.b); | ||
341 | evas_object_size_hint_align_get(child, &opt->align.h, &opt->align.v); | ||
342 | evas_object_size_hint_weight_get(child, &weightw, &weighth); | ||
343 | |||
344 | child_minw = opt->min.w + opt->pad.l + opt->pad.r; | ||
345 | child_minh = opt->min.h + opt->pad.t + opt->pad.b; | ||
346 | |||
347 | cell_minw = (child_minw + opt->colspan - 1) / opt->colspan; | ||
348 | cell_minh = (child_minh + opt->rowspan - 1) / opt->rowspan; | ||
349 | |||
350 | opt->expand_h = 0; | ||
351 | if ((weightw > 0.0) && | ||
352 | ((opt->max.w < 0) || | ||
353 | ((opt->max.w > -1) && (opt->min.w < opt->max.w)))) | ||
354 | { | ||
355 | opt->expand_h = 1; | ||
356 | expand_h = 1; | ||
357 | } | ||
358 | |||
359 | opt->expand_v = 0; | ||
360 | if ((weighth > 0.0) && | ||
361 | ((opt->max.h < 0) || | ||
362 | ((opt->max.h > -1) && (opt->min.h < opt->max.h)))) | ||
363 | { | ||
364 | opt->expand_v = 1; | ||
365 | expand_v = 1; | ||
366 | } | ||
367 | |||
368 | opt->fill_h = 0; | ||
369 | if (opt->align.h < 0.0) | ||
370 | { | ||
371 | opt->align.h = 0.5; | ||
372 | opt->fill_h = 1; | ||
373 | } | ||
374 | opt->fill_v = 0; | ||
375 | if (opt->align.v < 0.0) | ||
376 | { | ||
377 | opt->align.v = 0.5; | ||
378 | opt->fill_v = 1; | ||
379 | } | ||
380 | |||
381 | /* greatest mininum values, with paddings */ | ||
382 | if (minw < cell_minw) | ||
383 | minw = cell_minw; | ||
384 | if (minh < cell_minh) | ||
385 | minh = cell_minh; | ||
386 | /* greatest mininum values, without paddings */ | ||
387 | if (o_minw < opt->min.w) | ||
388 | o_minw = opt->min.w; | ||
389 | if (o_minh < opt->min.h) | ||
390 | o_minh = opt->min.h; | ||
391 | } | ||
392 | |||
393 | if (priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM) | ||
394 | { | ||
395 | if (o_minw < 1) | ||
396 | { | ||
397 | ERR("homogeneous table based on item size but no " | ||
398 | "horizontal mininum size specified! Using expand."); | ||
399 | expand_h = 1; | ||
400 | } | ||
401 | if (o_minh < 1) | ||
402 | { | ||
403 | ERR("homogeneous table based on item size but no " | ||
404 | "vertical mininum size specified! Using expand."); | ||
405 | expand_v = 1; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | minw = priv->size.cols * (minw + priv->pad.h) - priv->pad.h; | ||
410 | minh = priv->size.rows * (minh + priv->pad.v) - priv->pad.v; | ||
411 | |||
412 | priv->hints_changed = 0; | ||
413 | priv->expand_h = expand_h; | ||
414 | priv->expand_v = expand_v; | ||
415 | |||
416 | if ((minw > 0 ) || (minh > 0)) | ||
417 | evas_object_size_hint_min_set(o, minw, minh); | ||
418 | |||
419 | // XXX hint max? | ||
420 | } | ||
421 | |||
422 | static void | ||
423 | _evas_object_table_calculate_layout_homogeneous_sizes_item(const Evas_Object *o, const Evas_Object_Table_Data *priv, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) | ||
424 | { | ||
425 | Evas_Coord minw, minh; | ||
426 | Eina_Bool expand_h, expand_v; | ||
427 | |||
428 | evas_object_size_hint_min_get(o, &minw, &minh); | ||
429 | expand_h = priv->expand_h; | ||
430 | expand_v = priv->expand_v; | ||
431 | |||
432 | if (*w < minw) | ||
433 | expand_h = 0; | ||
434 | if (!expand_h) | ||
435 | { | ||
436 | *x += (*w - minw) * priv->align.h; | ||
437 | *w = minw; | ||
438 | } | ||
439 | |||
440 | if (*h < minh) | ||
441 | expand_v = 0; | ||
442 | if (!expand_v) | ||
443 | { | ||
444 | *y += (*h - minh) * priv->align.v; | ||
445 | *h = minh; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | static void | ||
450 | _evas_object_table_calculate_layout_homogeneous_sizes(const Evas_Object *o, const Evas_Object_Table_Data *priv, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h, Evas_Coord *cellw, Evas_Coord *cellh) | ||
451 | { | ||
452 | evas_object_geometry_get(o, x, y, w, h); | ||
453 | if (priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM) | ||
454 | _evas_object_table_calculate_layout_homogeneous_sizes_item | ||
455 | (o, priv, x, y, w, h); | ||
456 | |||
457 | *cellw = (*w + priv->size.cols - 1) / priv->size.cols; | ||
458 | *cellh = (*h + priv->size.rows - 1) / priv->size.rows; | ||
459 | } | ||
460 | |||
461 | static void | ||
462 | _evas_object_table_calculate_layout_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv) | ||
463 | { | ||
464 | Evas_Coord x = 0, y = 0, w = 0, h = 0, ww, hh, cellw = 0, cellh = 0; | ||
465 | Eina_List *l; | ||
466 | Evas_Object_Table_Option *opt; | ||
467 | |||
468 | _evas_object_table_calculate_layout_homogeneous_sizes | ||
469 | (o, priv, &x, &y, &w, &h, &cellw, &cellh); | ||
470 | |||
471 | ww = w - ((priv->size.cols - 1) * priv->pad.h); | ||
472 | hh = h - ((priv->size.rows - 1) * priv->pad.v); | ||
473 | |||
474 | if (ww < 0) ww = 0; | ||
475 | if (ww < 0) ww = 0; | ||
476 | |||
477 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
478 | { | ||
479 | Evas_Object *child = opt->obj; | ||
480 | Evas_Coord cx, cy, cw, ch, cox, coy, cow, coh; | ||
481 | |||
482 | cx = x + ((opt->col * ww) / priv->size.cols); | ||
483 | cw = x + (((opt->col + opt->colspan) * ww) / priv->size.cols) - cx; | ||
484 | cy = y + ((opt->row * hh) / priv->size.rows); | ||
485 | ch = y + (((opt->row + opt->rowspan) * hh) / priv->size.rows) - cy; | ||
486 | |||
487 | cx += (opt->col) * priv->pad.h; | ||
488 | cy += (opt->row) * priv->pad.v; | ||
489 | |||
490 | cox = cx; | ||
491 | coy = cy; | ||
492 | cow = cw; | ||
493 | coh = ch; | ||
494 | |||
495 | _evas_object_table_calculate_cell(opt, &cx, &cy, &cw, &ch); | ||
496 | if (cw > cow) | ||
497 | { | ||
498 | cx = cox; | ||
499 | cw = cow; | ||
500 | } | ||
501 | if (ch > coh) | ||
502 | { | ||
503 | cy = coy; | ||
504 | ch = coh; | ||
505 | } | ||
506 | |||
507 | if (priv->is_mirrored) | ||
508 | { | ||
509 | evas_object_move(opt->obj, x + w - (cx - x + cw), cy); | ||
510 | } | ||
511 | else | ||
512 | { | ||
513 | evas_object_move(child, cx, cy); | ||
514 | } | ||
515 | evas_object_resize(child, cw, ch); | ||
516 | } | ||
517 | } | ||
518 | |||
519 | static void | ||
520 | _evas_object_table_smart_calculate_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv) | ||
521 | { | ||
522 | if (priv->hints_changed) | ||
523 | _evas_object_table_calculate_hints_homogeneous(o, priv); | ||
524 | _evas_object_table_calculate_layout_homogeneous(o, priv); | ||
525 | } | ||
526 | |||
527 | static int | ||
528 | _evas_object_table_count_expands(const Eina_Bool *expands, int start, int end) | ||
529 | { | ||
530 | const Eina_Bool *itr = expands + start, *itr_end = expands + end; | ||
531 | int count = 0; | ||
532 | |||
533 | for (; itr < itr_end; itr++) | ||
534 | { | ||
535 | if (*itr) | ||
536 | count++; | ||
537 | } | ||
538 | |||
539 | return count; | ||
540 | } | ||
541 | |||
542 | static Evas_Coord | ||
543 | _evas_object_table_sum_sizes(const Evas_Coord *sizes, int start, int end) | ||
544 | { | ||
545 | const Evas_Coord *itr = sizes + start, *itr_end = sizes + end; | ||
546 | Evas_Coord sum = 0; | ||
547 | |||
548 | for (; itr < itr_end; itr++) | ||
549 | sum += *itr; | ||
550 | |||
551 | return sum; | ||
552 | } | ||
553 | |||
554 | static void | ||
555 | _evas_object_table_sizes_calc_noexpand(Evas_Coord *sizes, int start, int end, Evas_Coord space) | ||
556 | { | ||
557 | Evas_Coord *itr = sizes + start, *itr_end = sizes + end - 1; | ||
558 | Evas_Coord step; | ||
559 | int units; | ||
560 | |||
561 | /* XXX move to fixed point math and spread errors among cells */ | ||
562 | units = end - start; | ||
563 | step = space / units; | ||
564 | for (; itr < itr_end; itr++) | ||
565 | *itr += step; | ||
566 | |||
567 | *itr += space - step * (units - 1); | ||
568 | } | ||
569 | |||
570 | static void | ||
571 | _evas_object_table_sizes_calc_expand(Evas_Coord *sizes, int start, int end, Evas_Coord space, const Eina_Bool *expands, int expand_count, double *weights, double weighttot) | ||
572 | { | ||
573 | Evas_Coord *itr = sizes + start, *itr_end = sizes + end; | ||
574 | const Eina_Bool *itr_expand = expands + start; | ||
575 | Evas_Coord step = 0, last_space = 0; | ||
576 | int total = 0, i = start; | ||
577 | |||
578 | /* XXX move to fixed point math and spread errors among cells */ | ||
579 | if (weighttot > 0.0) | ||
580 | { | ||
581 | step = space / expand_count; | ||
582 | last_space = space - step * (expand_count - 1); | ||
583 | } | ||
584 | |||
585 | for (; itr < itr_end; itr++, itr_expand++, i++) | ||
586 | { | ||
587 | if (weighttot <= 0.0) | ||
588 | { | ||
589 | if (*itr_expand) | ||
590 | { | ||
591 | expand_count--; | ||
592 | if (expand_count > 0) | ||
593 | *itr += step; | ||
594 | else | ||
595 | { | ||
596 | *itr += last_space; | ||
597 | break; | ||
598 | } | ||
599 | } | ||
600 | } | ||
601 | else | ||
602 | { | ||
603 | if (*itr_expand) | ||
604 | { | ||
605 | expand_count--; | ||
606 | if (expand_count > 0) | ||
607 | { | ||
608 | step = (weights[i] / weighttot) * space; | ||
609 | *itr += step; | ||
610 | total += step; | ||
611 | } | ||
612 | else | ||
613 | { | ||
614 | *itr += space - total; | ||
615 | break; | ||
616 | } | ||
617 | } | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | |||
622 | static void | ||
623 | _evas_object_table_calculate_hints_regular(Evas_Object *o, Evas_Object_Table_Data *priv) | ||
624 | { | ||
625 | Evas_Object_Table_Option *opt; | ||
626 | Evas_Object_Table_Cache *c; | ||
627 | Eina_List *l; | ||
628 | double totweightw = 0.0, totweighth = 0.0; | ||
629 | int i; | ||
630 | |||
631 | if (!priv->cache) | ||
632 | { | ||
633 | priv->cache = _evas_object_table_cache_alloc | ||
634 | (priv->size.cols, priv->size.rows); | ||
635 | if (!priv->cache) | ||
636 | return; | ||
637 | } | ||
638 | c = priv->cache; | ||
639 | _evas_object_table_cache_reset(priv); | ||
640 | |||
641 | /* cache interesting data */ | ||
642 | memset(c->expands.h, 1, priv->size.cols); | ||
643 | memset(c->expands.v, 1, priv->size.rows); | ||
644 | memset(c->weights.h, 0, priv->size.cols); | ||
645 | memset(c->weights.v, 0, priv->size.rows); | ||
646 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
647 | { | ||
648 | Evas_Object *child = opt->obj; | ||
649 | double weightw, weighth; | ||
650 | |||
651 | evas_object_size_hint_min_get(child, &opt->min.w, &opt->min.h); | ||
652 | evas_object_size_hint_max_get(child, &opt->max.w, &opt->max.h); | ||
653 | evas_object_size_hint_padding_get | ||
654 | (child, &opt->pad.l, &opt->pad.r, &opt->pad.t, &opt->pad.b); | ||
655 | evas_object_size_hint_align_get(child, &opt->align.h, &opt->align.v); | ||
656 | evas_object_size_hint_weight_get(child, &weightw, &weighth); | ||
657 | |||
658 | opt->expand_h = 0; | ||
659 | if ((weightw > 0.0) && | ||
660 | ((opt->max.w < 0) || | ||
661 | ((opt->max.w > -1) && (opt->min.w < opt->max.w)))) | ||
662 | opt->expand_h = 1; | ||
663 | |||
664 | opt->expand_v = 0; | ||
665 | if ((weighth > 0.0) && | ||
666 | ((opt->max.h < 0) || | ||
667 | ((opt->max.h > -1) && (opt->min.h < opt->max.h)))) | ||
668 | opt->expand_v = 1; | ||
669 | |||
670 | opt->fill_h = 0; | ||
671 | if (opt->align.h < 0.0) | ||
672 | { | ||
673 | opt->align.h = 0.5; | ||
674 | opt->fill_h = 1; | ||
675 | } | ||
676 | opt->fill_v = 0; | ||
677 | if (opt->align.v < 0.0) | ||
678 | { | ||
679 | opt->align.v = 0.5; | ||
680 | opt->fill_v = 1; | ||
681 | } | ||
682 | |||
683 | if (!opt->expand_h) | ||
684 | memset(c->expands.h + opt->col, 0, opt->colspan); | ||
685 | else | ||
686 | { | ||
687 | for (i = opt->col; i < opt->col + opt->colspan; i++) | ||
688 | c->weights.h[i] += (weightw / (double)opt->colspan); | ||
689 | } | ||
690 | if (!opt->expand_v) | ||
691 | memset(c->expands.v + opt->row, 0, opt->rowspan); | ||
692 | else | ||
693 | { | ||
694 | for (i = opt->row; i < opt->row + opt->rowspan; i++) | ||
695 | c->weights.v[i] += (weighth / (double)opt->rowspan); | ||
696 | } | ||
697 | } | ||
698 | for (i = 0; i < priv->size.cols; i++) totweightw += c->weights.h[i]; | ||
699 | for (i = 0; i < priv->size.rows; i++) totweighth += c->weights.v[i]; | ||
700 | |||
701 | /* calculate sizes for each row and column */ | ||
702 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
703 | { | ||
704 | Evas_Coord tot, need; | ||
705 | |||
706 | /* handle horizontal */ | ||
707 | tot = _evas_object_table_sum_sizes(c->sizes.h, opt->col, opt->end_col); | ||
708 | need = opt->min.w + opt->pad.l + opt->pad.r; | ||
709 | if (tot < need) | ||
710 | { | ||
711 | Evas_Coord space = need - tot; | ||
712 | int count; | ||
713 | |||
714 | count = _evas_object_table_count_expands | ||
715 | (c->expands.h, opt->col, opt->end_col); | ||
716 | |||
717 | if (count > 0) | ||
718 | _evas_object_table_sizes_calc_expand | ||
719 | (c->sizes.h, opt->col, opt->end_col, space, | ||
720 | c->expands.h, count, c->weights.h, totweightw); | ||
721 | else | ||
722 | _evas_object_table_sizes_calc_noexpand | ||
723 | (c->sizes.h, opt->col, opt->end_col, space); | ||
724 | } | ||
725 | |||
726 | /* handle vertical */ | ||
727 | tot = _evas_object_table_sum_sizes(c->sizes.v, opt->row, opt->end_row); | ||
728 | need = opt->min.h + opt->pad.t + opt->pad.b; | ||
729 | if (tot < opt->min.h) | ||
730 | { | ||
731 | Evas_Coord space = need - tot; | ||
732 | int count; | ||
733 | |||
734 | count = _evas_object_table_count_expands | ||
735 | (c->expands.v, opt->row, opt->end_row); | ||
736 | |||
737 | if (count > 0) | ||
738 | _evas_object_table_sizes_calc_expand | ||
739 | (c->sizes.v, opt->row, opt->end_row, space, | ||
740 | c->expands.v, count, c->weights.v, totweighth); | ||
741 | else | ||
742 | _evas_object_table_sizes_calc_noexpand | ||
743 | (c->sizes.v, opt->row, opt->end_row, space); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | c->total.weights.h = totweightw; | ||
748 | c->total.weights.v = totweighth; | ||
749 | |||
750 | c->total.expands.h = _evas_object_table_count_expands | ||
751 | (c->expands.h, 0, priv->size.cols); | ||
752 | c->total.expands.v = _evas_object_table_count_expands | ||
753 | (c->expands.v, 0, priv->size.rows); | ||
754 | |||
755 | c->total.min.w = _evas_object_table_sum_sizes | ||
756 | (c->sizes.h, 0, priv->size.cols); | ||
757 | c->total.min.h = _evas_object_table_sum_sizes | ||
758 | (c->sizes.v, 0, priv->size.rows); | ||
759 | |||
760 | c->total.min.w += priv->pad.h * (priv->size.cols - 1); | ||
761 | c->total.min.h += priv->pad.v * (priv->size.rows - 1); | ||
762 | |||
763 | if ((c->total.min.w > 0) || (c->total.min.h > 0)) | ||
764 | evas_object_size_hint_min_set(o, c->total.min.w, c->total.min.h); | ||
765 | |||
766 | // XXX hint max? | ||
767 | } | ||
768 | |||
769 | static void | ||
770 | _evas_object_table_calculate_layout_regular(Evas_Object *o, Evas_Object_Table_Data *priv) | ||
771 | { | ||
772 | Evas_Object_Table_Option *opt; | ||
773 | Evas_Object_Table_Cache *c; | ||
774 | Eina_List *l; | ||
775 | Evas_Coord *cols = NULL, *rows = NULL; | ||
776 | Evas_Coord x, y, w, h; | ||
777 | |||
778 | evas_object_geometry_get(o, &x, &y, &w, &h); | ||
779 | c = priv->cache; | ||
780 | |||
781 | /* handle horizontal */ | ||
782 | if ((c->total.expands.h <= 0) || (c->total.min.w >= w)) | ||
783 | { | ||
784 | x += (w - c->total.min.w) * priv->align.h; | ||
785 | w = c->total.min.w; | ||
786 | cols = c->sizes.h; | ||
787 | } | ||
788 | else | ||
789 | { | ||
790 | int size = priv->size.cols * sizeof(Evas_Coord); | ||
791 | cols = malloc(size); | ||
792 | if (!cols) | ||
793 | { | ||
794 | ERR("Could not allocate temp columns (%d bytes): %s", | ||
795 | size, strerror(errno)); | ||
796 | goto end; | ||
797 | } | ||
798 | memcpy(cols, c->sizes.h, size); | ||
799 | _evas_object_table_sizes_calc_expand | ||
800 | (cols, 0, priv->size.cols, w - c->total.min.w, | ||
801 | c->expands.h, c->total.expands.h, c->weights.h, c->total.weights.h); | ||
802 | } | ||
803 | |||
804 | /* handle vertical */ | ||
805 | if ((c->total.expands.v <= 0) || (c->total.min.h >= h)) | ||
806 | { | ||
807 | y += (h - c->total.min.h) * priv->align.v; | ||
808 | h = c->total.min.h; | ||
809 | rows = c->sizes.v; | ||
810 | } | ||
811 | else | ||
812 | { | ||
813 | int size = priv->size.rows * sizeof(Evas_Coord); | ||
814 | rows = malloc(size); | ||
815 | if (!rows) | ||
816 | { | ||
817 | ERR("could not allocate temp rows (%d bytes): %s", | ||
818 | size, strerror(errno)); | ||
819 | goto end; | ||
820 | } | ||
821 | memcpy(rows, c->sizes.v, size); | ||
822 | _evas_object_table_sizes_calc_expand | ||
823 | (rows, 0, priv->size.rows, h - c->total.min.h, | ||
824 | c->expands.v, c->total.expands.v, c->weights.v, c->total.weights.v); | ||
825 | } | ||
826 | |||
827 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
828 | { | ||
829 | Evas_Object *child = opt->obj; | ||
830 | Evas_Coord cx, cy, cw, ch; | ||
831 | |||
832 | cx = x + opt->col * (priv->pad.h); | ||
833 | cx += _evas_object_table_sum_sizes(cols, 0, opt->col); | ||
834 | cw = _evas_object_table_sum_sizes(cols, opt->col, opt->end_col); | ||
835 | |||
836 | cy = y + opt->row * (priv->pad.v); | ||
837 | cy += _evas_object_table_sum_sizes(rows, 0, opt->row); | ||
838 | ch = _evas_object_table_sum_sizes(rows, opt->row, opt->end_row); | ||
839 | |||
840 | _evas_object_table_calculate_cell(opt, &cx, &cy, &cw, &ch); | ||
841 | |||
842 | if (priv->is_mirrored) | ||
843 | { | ||
844 | evas_object_move(opt->obj, x + w - (cx - x + cw), cy); | ||
845 | } | ||
846 | else | ||
847 | { | ||
848 | evas_object_move(child, cx, cy); | ||
849 | } | ||
850 | evas_object_resize(child, cw, ch); | ||
851 | } | ||
852 | |||
853 | end: | ||
854 | if (cols != c->sizes.h) | ||
855 | { | ||
856 | if (cols) free(cols); | ||
857 | } | ||
858 | if (rows != c->sizes.v) | ||
859 | { | ||
860 | if (rows) free(rows); | ||
861 | } | ||
862 | } | ||
863 | |||
864 | static void | ||
865 | _evas_object_table_smart_calculate_regular(Evas_Object *o, Evas_Object_Table_Data *priv) | ||
866 | { | ||
867 | if (priv->hints_changed) | ||
868 | _evas_object_table_calculate_hints_regular(o, priv); | ||
869 | _evas_object_table_calculate_layout_regular(o, priv); | ||
870 | } | ||
871 | |||
872 | EVAS_SMART_SUBCLASS_NEW("Evas_Object_Table", _evas_object_table, | ||
873 | Evas_Smart_Class, Evas_Smart_Class, | ||
874 | evas_object_smart_clipped_class_get, NULL) | ||
875 | |||
876 | static void | ||
877 | _evas_object_table_smart_add(Evas_Object *o) | ||
878 | { | ||
879 | EVAS_SMART_DATA_ALLOC(o, Evas_Object_Table_Data) | ||
880 | |||
881 | priv->pad.h = 0; | ||
882 | priv->pad.v = 0; | ||
883 | priv->align.h = 0.5; | ||
884 | priv->align.v = 0.5; | ||
885 | priv->size.cols = 0; | ||
886 | priv->size.rows = 0; | ||
887 | priv->cache = NULL; | ||
888 | priv->homogeneous = EVAS_OBJECT_TABLE_HOMOGENEOUS_NONE; | ||
889 | priv->hints_changed = 1; | ||
890 | priv->expand_h = 0; | ||
891 | priv->expand_v = 0; | ||
892 | |||
893 | _evas_object_table_parent_sc->add(o); | ||
894 | } | ||
895 | |||
896 | static void | ||
897 | _evas_object_table_smart_del(Evas_Object *o) | ||
898 | { | ||
899 | EVAS_OBJECT_TABLE_DATA_GET(o, priv); | ||
900 | Eina_List *l; | ||
901 | |||
902 | l = priv->children; | ||
903 | while (l) | ||
904 | { | ||
905 | Evas_Object_Table_Option *opt = l->data; | ||
906 | _evas_object_table_child_disconnect(o, opt->obj); | ||
907 | _evas_object_table_option_del(opt->obj); | ||
908 | free(opt); | ||
909 | l = eina_list_remove_list(l, l); | ||
910 | } | ||
911 | |||
912 | if (priv->cache) | ||
913 | { | ||
914 | _evas_object_table_cache_free(priv->cache); | ||
915 | priv->cache = NULL; | ||
916 | } | ||
917 | |||
918 | _evas_object_table_parent_sc->del(o); | ||
919 | } | ||
920 | |||
921 | static void | ||
922 | _evas_object_table_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h) | ||
923 | { | ||
924 | Evas_Coord ow, oh; | ||
925 | evas_object_geometry_get(o, NULL, NULL, &ow, &oh); | ||
926 | if ((ow == w) && (oh == h)) return; | ||
927 | evas_object_smart_changed(o); | ||
928 | } | ||
929 | |||
930 | static void | ||
931 | _evas_object_table_smart_calculate(Evas_Object *o) | ||
932 | { | ||
933 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv); | ||
934 | |||
935 | if ((priv->size.cols < 1) || (priv->size.rows < 1)) | ||
936 | { | ||
937 | DBG("Nothing to do: cols=%d, rows=%d", | ||
938 | priv->size.cols, priv->size.rows); | ||
939 | return; | ||
940 | } | ||
941 | |||
942 | if (priv->homogeneous) | ||
943 | _evas_object_table_smart_calculate_homogeneous(o, priv); | ||
944 | else | ||
945 | _evas_object_table_smart_calculate_regular(o, priv); | ||
946 | } | ||
947 | |||
948 | static void | ||
949 | _evas_object_table_smart_set_user(Evas_Smart_Class *sc) | ||
950 | { | ||
951 | sc->add = _evas_object_table_smart_add; | ||
952 | sc->del = _evas_object_table_smart_del; | ||
953 | sc->resize = _evas_object_table_smart_resize; | ||
954 | sc->calculate = _evas_object_table_smart_calculate; | ||
955 | } | ||
956 | |||
957 | EAPI Evas_Object * | ||
958 | evas_object_table_add(Evas *evas) | ||
959 | { | ||
960 | return evas_object_smart_add(evas, _evas_object_table_smart_class_new()); | ||
961 | } | ||
962 | |||
963 | EAPI Evas_Object * | ||
964 | evas_object_table_add_to(Evas_Object *parent) | ||
965 | { | ||
966 | Evas *evas; | ||
967 | Evas_Object *o; | ||
968 | |||
969 | evas = evas_object_evas_get(parent); | ||
970 | o = evas_object_table_add(evas); | ||
971 | evas_object_smart_member_add(o, parent); | ||
972 | return o; | ||
973 | } | ||
974 | |||
975 | EAPI void | ||
976 | evas_object_table_homogeneous_set(Evas_Object *o, Evas_Object_Table_Homogeneous_Mode homogeneous) | ||
977 | { | ||
978 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv); | ||
979 | if (priv->homogeneous == homogeneous) | ||
980 | return; | ||
981 | priv->homogeneous = homogeneous; | ||
982 | _evas_object_table_cache_invalidate(priv); | ||
983 | evas_object_smart_changed(o); | ||
984 | } | ||
985 | |||
986 | EAPI Evas_Object_Table_Homogeneous_Mode | ||
987 | evas_object_table_homogeneous_get(const Evas_Object *o) | ||
988 | { | ||
989 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
990 | return priv->homogeneous; | ||
991 | } | ||
992 | |||
993 | EAPI void | ||
994 | evas_object_table_align_set(Evas_Object *o, double horizontal, double vertical) | ||
995 | { | ||
996 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv); | ||
997 | if (priv->align.h == horizontal && priv->align.v == vertical) | ||
998 | return; | ||
999 | priv->align.h = horizontal; | ||
1000 | priv->align.v = vertical; | ||
1001 | evas_object_smart_changed(o); | ||
1002 | } | ||
1003 | |||
1004 | EAPI void | ||
1005 | evas_object_table_align_get(const Evas_Object *o, double *horizontal, double *vertical) | ||
1006 | { | ||
1007 | EVAS_OBJECT_TABLE_DATA_GET(o, priv); | ||
1008 | if (priv) | ||
1009 | { | ||
1010 | if (horizontal) *horizontal = priv->align.h; | ||
1011 | if (vertical) *vertical = priv->align.v; | ||
1012 | } | ||
1013 | else | ||
1014 | { | ||
1015 | if (horizontal) *horizontal = 0.5; | ||
1016 | if (vertical) *vertical = 0.5; | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | EAPI void | ||
1021 | evas_object_table_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical) | ||
1022 | { | ||
1023 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv); | ||
1024 | if (priv->pad.h == horizontal && priv->pad.v == vertical) | ||
1025 | return; | ||
1026 | priv->pad.h = horizontal; | ||
1027 | priv->pad.v = vertical; | ||
1028 | _evas_object_table_cache_invalidate(priv); | ||
1029 | evas_object_smart_changed(o); | ||
1030 | } | ||
1031 | |||
1032 | EAPI void | ||
1033 | evas_object_table_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical) | ||
1034 | { | ||
1035 | EVAS_OBJECT_TABLE_DATA_GET(o, priv); | ||
1036 | if (priv) | ||
1037 | { | ||
1038 | if (horizontal) *horizontal = priv->pad.h; | ||
1039 | if (vertical) *vertical = priv->pad.v; | ||
1040 | } | ||
1041 | else | ||
1042 | { | ||
1043 | if (horizontal) *horizontal = 0; | ||
1044 | if (vertical) *vertical = 0; | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | EAPI Eina_Bool | ||
1049 | evas_object_table_pack_get(Evas_Object *o, Evas_Object *child, unsigned short *col, unsigned short *row, unsigned short *colspan, unsigned short *rowspan) | ||
1050 | { | ||
1051 | Evas_Object_Table_Option *opt; | ||
1052 | |||
1053 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1054 | opt = _evas_object_table_option_get(child); | ||
1055 | if (!opt) | ||
1056 | { | ||
1057 | if (col) *col = 0; | ||
1058 | if (row) *row = 0; | ||
1059 | if (colspan) *colspan = 0; | ||
1060 | if (rowspan) *rowspan = 0; | ||
1061 | return EINA_FALSE; | ||
1062 | } | ||
1063 | if (col) *col = opt->col; | ||
1064 | if (row) *row = opt->row; | ||
1065 | if (colspan) *colspan = opt->colspan; | ||
1066 | if (rowspan) *rowspan = opt->rowspan; | ||
1067 | return EINA_TRUE; | ||
1068 | } | ||
1069 | |||
1070 | EAPI Eina_Bool | ||
1071 | evas_object_table_pack(Evas_Object *o, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan) | ||
1072 | { | ||
1073 | Evas_Object_Table_Option *opt; | ||
1074 | |||
1075 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1076 | |||
1077 | if (rowspan < 1) | ||
1078 | { | ||
1079 | ERR("rowspan < 1"); | ||
1080 | return EINA_FALSE; | ||
1081 | } | ||
1082 | if (colspan < 1) | ||
1083 | { | ||
1084 | ERR("colspan < 1"); | ||
1085 | return EINA_FALSE; | ||
1086 | } | ||
1087 | |||
1088 | opt = _evas_object_table_option_get(child); | ||
1089 | if (!opt) | ||
1090 | { | ||
1091 | opt = malloc(sizeof(*opt)); | ||
1092 | if (!opt) | ||
1093 | { | ||
1094 | ERR("could not allocate table option data."); | ||
1095 | return EINA_FALSE; | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | opt->obj = child; | ||
1100 | opt->col = col; | ||
1101 | opt->row = row; | ||
1102 | opt->colspan = colspan; | ||
1103 | opt->rowspan = rowspan; | ||
1104 | opt->end_col = col + colspan; | ||
1105 | opt->end_row = row + rowspan; | ||
1106 | |||
1107 | if (evas_object_smart_parent_get(child) == o) | ||
1108 | { | ||
1109 | Eina_Bool need_shrink = EINA_FALSE; | ||
1110 | |||
1111 | if (priv->size.cols < opt->end_col) | ||
1112 | priv->size.cols = opt->end_col; | ||
1113 | else | ||
1114 | need_shrink = EINA_TRUE; | ||
1115 | if (priv->size.rows < opt->end_row) | ||
1116 | priv->size.rows = opt->end_row; | ||
1117 | else | ||
1118 | need_shrink = EINA_TRUE; | ||
1119 | |||
1120 | if (need_shrink) | ||
1121 | { | ||
1122 | Eina_List *l; | ||
1123 | Evas_Object_Table_Option *opt2; | ||
1124 | int max_row = 0, max_col = 0; | ||
1125 | |||
1126 | EINA_LIST_FOREACH(priv->children, l, opt2) | ||
1127 | { | ||
1128 | if (max_col < opt2->end_col) max_col = opt2->end_col; | ||
1129 | if (max_row < opt2->end_row) max_row = opt2->end_row; | ||
1130 | } | ||
1131 | priv->size.cols = max_col; | ||
1132 | priv->size.rows = max_row; | ||
1133 | } | ||
1134 | } | ||
1135 | else | ||
1136 | { | ||
1137 | opt->min.w = 0; | ||
1138 | opt->min.h = 0; | ||
1139 | opt->max.w = 0; | ||
1140 | opt->max.h = 0; | ||
1141 | opt->align.h = 0.5; | ||
1142 | opt->align.v = 0.5; | ||
1143 | opt->pad.l = 0; | ||
1144 | opt->pad.r = 0; | ||
1145 | opt->pad.t = 0; | ||
1146 | opt->pad.b = 0; | ||
1147 | opt->expand_h = 0; | ||
1148 | opt->expand_v = 0; | ||
1149 | |||
1150 | priv->children = eina_list_append(priv->children, opt); | ||
1151 | |||
1152 | if (priv->size.cols < opt->end_col) | ||
1153 | priv->size.cols = opt->end_col; | ||
1154 | if (priv->size.rows < opt->end_row) | ||
1155 | priv->size.rows = opt->end_row; | ||
1156 | |||
1157 | _evas_object_table_option_set(child, opt); | ||
1158 | evas_object_smart_member_add(child, o); | ||
1159 | _evas_object_table_child_connect(o, child); | ||
1160 | } | ||
1161 | _evas_object_table_cache_invalidate(priv); | ||
1162 | evas_object_smart_changed(o); | ||
1163 | return EINA_TRUE; | ||
1164 | } | ||
1165 | |||
1166 | static void | ||
1167 | _evas_object_table_remove_opt(Evas_Object_Table_Data *priv, Evas_Object_Table_Option *opt) | ||
1168 | { | ||
1169 | Eina_List *l; | ||
1170 | int max_row, max_col, was_greatest; | ||
1171 | |||
1172 | max_row = 0; | ||
1173 | max_col = 0; | ||
1174 | was_greatest = 0; | ||
1175 | l = priv->children; | ||
1176 | while (l) | ||
1177 | { | ||
1178 | Evas_Object_Table_Option *cur_opt = l->data; | ||
1179 | |||
1180 | if (cur_opt != opt) | ||
1181 | { | ||
1182 | if (max_col < cur_opt->end_col) | ||
1183 | max_col = cur_opt->end_col; | ||
1184 | if (max_row < cur_opt->end_row) | ||
1185 | max_row = cur_opt->end_row; | ||
1186 | |||
1187 | l = l->next; | ||
1188 | } | ||
1189 | else | ||
1190 | { | ||
1191 | Eina_List *tmp = l->next; | ||
1192 | priv->children = eina_list_remove_list(priv->children, l); | ||
1193 | |||
1194 | if ((priv->size.cols > opt->end_col) && | ||
1195 | (priv->size.rows > opt->end_row)) | ||
1196 | break; | ||
1197 | else | ||
1198 | { | ||
1199 | was_greatest = 1; | ||
1200 | l = tmp; | ||
1201 | } | ||
1202 | } | ||
1203 | } | ||
1204 | |||
1205 | if (was_greatest) | ||
1206 | { | ||
1207 | priv->size.cols = max_col; | ||
1208 | priv->size.rows = max_row; | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | EAPI Eina_Bool | ||
1213 | evas_object_table_unpack(Evas_Object *o, Evas_Object *child) | ||
1214 | { | ||
1215 | Evas_Object_Table_Option *opt; | ||
1216 | |||
1217 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0); | ||
1218 | |||
1219 | if (o != evas_object_smart_parent_get(child)) | ||
1220 | { | ||
1221 | ERR("cannot unpack child from incorrect table!"); | ||
1222 | return EINA_FALSE; | ||
1223 | } | ||
1224 | |||
1225 | opt = _evas_object_table_option_del(child); | ||
1226 | if (!opt) | ||
1227 | { | ||
1228 | ERR("cannot unpack child with no packing option!"); | ||
1229 | return EINA_FALSE; | ||
1230 | } | ||
1231 | |||
1232 | _evas_object_table_child_disconnect(o, child); | ||
1233 | _evas_object_table_remove_opt(priv, opt); | ||
1234 | evas_object_smart_member_del(child); | ||
1235 | free(opt); | ||
1236 | _evas_object_table_cache_invalidate(priv); | ||
1237 | evas_object_smart_changed(o); | ||
1238 | |||
1239 | return EINA_TRUE; | ||
1240 | } | ||
1241 | |||
1242 | EAPI void | ||
1243 | evas_object_table_clear(Evas_Object *o, Eina_Bool clear) | ||
1244 | { | ||
1245 | Evas_Object_Table_Option *opt; | ||
1246 | |||
1247 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv); | ||
1248 | |||
1249 | EINA_LIST_FREE(priv->children, opt) | ||
1250 | { | ||
1251 | _evas_object_table_child_disconnect(o, opt->obj); | ||
1252 | _evas_object_table_option_del(opt->obj); | ||
1253 | evas_object_smart_member_del(opt->obj); | ||
1254 | if (clear) | ||
1255 | evas_object_del(opt->obj); | ||
1256 | free(opt); | ||
1257 | } | ||
1258 | priv->size.cols = 0; | ||
1259 | priv->size.rows = 0; | ||
1260 | _evas_object_table_cache_invalidate(priv); | ||
1261 | evas_object_smart_changed(o); | ||
1262 | } | ||
1263 | |||
1264 | EAPI void | ||
1265 | evas_object_table_col_row_size_get(const Evas_Object *o, int *cols, int *rows) | ||
1266 | { | ||
1267 | EVAS_OBJECT_TABLE_DATA_GET(o, priv); | ||
1268 | if (priv) | ||
1269 | { | ||
1270 | if (cols) *cols = priv->size.cols; | ||
1271 | if (rows) *rows = priv->size.rows; | ||
1272 | } | ||
1273 | else | ||
1274 | { | ||
1275 | if (cols) *cols = -1; | ||
1276 | if (rows) *rows = -1; | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | EAPI Eina_Iterator * | ||
1281 | evas_object_table_iterator_new(const Evas_Object *o) | ||
1282 | { | ||
1283 | Evas_Object_Table_Iterator *it; | ||
1284 | |||
1285 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
1286 | |||
1287 | if (!priv->children) return NULL; | ||
1288 | |||
1289 | it = calloc(1, sizeof(Evas_Object_Table_Iterator)); | ||
1290 | if (!it) return NULL; | ||
1291 | |||
1292 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
1293 | |||
1294 | it->real_iterator = eina_list_iterator_new(priv->children); | ||
1295 | it->table = o; | ||
1296 | |||
1297 | it->iterator.next = FUNC_ITERATOR_NEXT(_evas_object_table_iterator_next); | ||
1298 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_evas_object_table_iterator_get_container); | ||
1299 | it->iterator.free = FUNC_ITERATOR_FREE(_evas_object_table_iterator_free); | ||
1300 | |||
1301 | return &it->iterator; | ||
1302 | } | ||
1303 | |||
1304 | EAPI Eina_Accessor * | ||
1305 | evas_object_table_accessor_new(const Evas_Object *o) | ||
1306 | { | ||
1307 | Evas_Object_Table_Accessor *it; | ||
1308 | |||
1309 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
1310 | |||
1311 | if (!priv->children) return NULL; | ||
1312 | |||
1313 | it = calloc(1, sizeof(Evas_Object_Table_Accessor)); | ||
1314 | if (!it) return NULL; | ||
1315 | |||
1316 | EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR); | ||
1317 | |||
1318 | it->real_accessor = eina_list_accessor_new(priv->children); | ||
1319 | it->table = o; | ||
1320 | |||
1321 | it->accessor.get_at = FUNC_ACCESSOR_GET_AT(_evas_object_table_accessor_get_at); | ||
1322 | it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(_evas_object_table_accessor_get_container); | ||
1323 | it->accessor.free = FUNC_ACCESSOR_FREE(_evas_object_table_accessor_free); | ||
1324 | |||
1325 | return &it->accessor; | ||
1326 | } | ||
1327 | |||
1328 | EAPI Eina_List * | ||
1329 | evas_object_table_children_get(const Evas_Object *o) | ||
1330 | { | ||
1331 | Eina_List *new_list = NULL, *l; | ||
1332 | Evas_Object_Table_Option *opt; | ||
1333 | |||
1334 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
1335 | |||
1336 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1337 | new_list = eina_list_append(new_list, opt->obj); | ||
1338 | |||
1339 | return new_list; | ||
1340 | } | ||
1341 | |||
1342 | Evas_Object * | ||
1343 | evas_object_table_child_get(const Evas_Object *o, unsigned short col, unsigned short row) | ||
1344 | { | ||
1345 | Eina_List *l; | ||
1346 | Evas_Object_Table_Option *opt; | ||
1347 | |||
1348 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL); | ||
1349 | |||
1350 | EINA_LIST_FOREACH(priv->children, l, opt) | ||
1351 | if (opt->col == col && opt->row == row) | ||
1352 | return opt->obj; | ||
1353 | return NULL; | ||
1354 | } | ||
1355 | |||
1356 | EAPI Eina_Bool | ||
1357 | evas_object_table_mirrored_get(const Evas_Object *obj) | ||
1358 | { | ||
1359 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(obj, priv, EINA_FALSE); | ||
1360 | |||
1361 | return priv->is_mirrored; | ||
1362 | } | ||
1363 | |||
1364 | EAPI void | ||
1365 | evas_object_table_mirrored_set(Evas_Object *obj, Eina_Bool mirrored) | ||
1366 | { | ||
1367 | EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(obj, priv); | ||
1368 | if (priv->is_mirrored != mirrored) | ||
1369 | { | ||
1370 | priv->is_mirrored = mirrored; | ||
1371 | _evas_object_table_smart_calculate(obj); | ||
1372 | } | ||
1373 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_object_text.c b/libraries/evas/src/lib/canvas/evas_object_text.c new file mode 100644 index 0000000..6c30fcc --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_text.c | |||
@@ -0,0 +1,1943 @@ | |||
1 | #include "evas_common.h" /* Includes evas_bidi_utils stuff. */ | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | /* save typing */ | ||
5 | #define ENFN obj->layer->evas->engine.func | ||
6 | #define ENDT obj->layer->evas->engine.data.output | ||
7 | |||
8 | /* private magic number for text objects */ | ||
9 | static const char o_type[] = "text"; | ||
10 | |||
11 | /* private struct for text object internal data */ | ||
12 | typedef struct _Evas_Object_Text Evas_Object_Text; | ||
13 | typedef struct _Evas_Object_Text_Item Evas_Object_Text_Item; | ||
14 | |||
15 | struct _Evas_Object_Text | ||
16 | { | ||
17 | DATA32 magic; | ||
18 | |||
19 | struct { | ||
20 | const char *utf8_text; /* The text exposed to the API */ | ||
21 | const char *font; | ||
22 | Evas_Font_Description *fdesc; | ||
23 | const char *source; | ||
24 | Evas_Font_Size size; | ||
25 | struct { | ||
26 | unsigned char r, g, b, a; | ||
27 | } outline, shadow, glow, glow2; | ||
28 | |||
29 | unsigned char style; | ||
30 | } cur, prev; | ||
31 | |||
32 | float ascent, descent; | ||
33 | float max_ascent, max_descent; | ||
34 | Evas_BiDi_Paragraph_Props *bidi_par_props; | ||
35 | const char *bidi_delimiters; | ||
36 | Evas_Object_Text_Item *items; | ||
37 | |||
38 | Evas_Font_Set *font; | ||
39 | |||
40 | char changed : 1; | ||
41 | }; | ||
42 | |||
43 | struct _Evas_Object_Text_Item | ||
44 | { | ||
45 | EINA_INLIST; | ||
46 | |||
47 | size_t text_pos; | ||
48 | size_t visual_pos; | ||
49 | Evas_Text_Props text_props; | ||
50 | Evas_Coord x, w, h, adv; | ||
51 | }; | ||
52 | |||
53 | /* private methods for text objects */ | ||
54 | static void evas_object_text_init(Evas_Object *obj); | ||
55 | static void *evas_object_text_new(void); | ||
56 | static void evas_object_text_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y); | ||
57 | static void evas_object_text_free(Evas_Object *obj); | ||
58 | static void evas_object_text_render_pre(Evas_Object *obj); | ||
59 | static void evas_object_text_render_post(Evas_Object *obj); | ||
60 | |||
61 | static unsigned int evas_object_text_id_get(Evas_Object *obj); | ||
62 | static unsigned int evas_object_text_visual_id_get(Evas_Object *obj); | ||
63 | static void *evas_object_text_engine_data_get(Evas_Object *obj); | ||
64 | |||
65 | static int evas_object_text_is_opaque(Evas_Object *obj); | ||
66 | static int evas_object_text_was_opaque(Evas_Object *obj); | ||
67 | |||
68 | static void evas_object_text_scale_update(Evas_Object *obj); | ||
69 | static void _evas_object_text_recalc(Evas_Object *obj); | ||
70 | |||
71 | static const Evas_Object_Func object_func = | ||
72 | { | ||
73 | /* methods (compulsory) */ | ||
74 | evas_object_text_free, | ||
75 | evas_object_text_render, | ||
76 | evas_object_text_render_pre, | ||
77 | evas_object_text_render_post, | ||
78 | evas_object_text_id_get, | ||
79 | evas_object_text_visual_id_get, | ||
80 | evas_object_text_engine_data_get, | ||
81 | /* these are optional. NULL = nothing */ | ||
82 | NULL, | ||
83 | NULL, | ||
84 | NULL, | ||
85 | NULL, | ||
86 | evas_object_text_is_opaque, | ||
87 | evas_object_text_was_opaque, | ||
88 | NULL, | ||
89 | NULL, | ||
90 | NULL, | ||
91 | evas_object_text_scale_update, | ||
92 | NULL, | ||
93 | NULL, | ||
94 | NULL | ||
95 | }; | ||
96 | |||
97 | /* the actual api call to add a rect */ | ||
98 | /* it has no other api calls as all properties are standard */ | ||
99 | |||
100 | EVAS_MEMPOOL(_mp_obj); | ||
101 | |||
102 | static int | ||
103 | _evas_object_text_char_coords_get(const Evas_Object *obj, | ||
104 | const Evas_Object_Text *o, | ||
105 | size_t pos, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h) | ||
106 | { | ||
107 | Evas_Object_Text_Item *it; | ||
108 | |||
109 | EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it) | ||
110 | { | ||
111 | if ((it->text_pos <= pos) && | ||
112 | (pos < (it->text_pos + it->text_props.text_len))) | ||
113 | { | ||
114 | int ret; | ||
115 | ret = ENFN->font_char_coords_get(ENDT, o->font, | ||
116 | &it->text_props, pos - it->text_pos, x, y, w, h); | ||
117 | if (x) *x += it->x; | ||
118 | return ret; | ||
119 | } | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void | ||
125 | _evas_object_text_item_clean(Evas_Object_Text_Item *it) | ||
126 | { | ||
127 | evas_common_text_props_content_unref(&it->text_props); | ||
128 | } | ||
129 | |||
130 | static void | ||
131 | _evas_object_text_items_clear(Evas_Object_Text *o) | ||
132 | { | ||
133 | Evas_Object_Text_Item *it; | ||
134 | |||
135 | while (o->items) | ||
136 | { | ||
137 | it = o->items; | ||
138 | o->items = (Evas_Object_Text_Item *) eina_inlist_remove( | ||
139 | EINA_INLIST_GET(o->items), | ||
140 | EINA_INLIST_GET(it)); | ||
141 | _evas_object_text_item_clean(it); | ||
142 | free(it); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | #ifdef BIDI_SUPPORT | ||
147 | static int | ||
148 | _evas_object_text_it_compare_logical(const void *_it1, const void *_it2) | ||
149 | { | ||
150 | const Evas_Object_Text_Item *it1 = _it1, *it2 = _it2; | ||
151 | if (it1->text_pos < it2->text_pos) | ||
152 | return -1; | ||
153 | else if (it1->text_pos == it2->text_pos) | ||
154 | return 0; | ||
155 | else | ||
156 | return 1; | ||
157 | |||
158 | } | ||
159 | #endif | ||
160 | |||
161 | static int | ||
162 | _evas_object_text_last_up_to_pos(const Evas_Object *obj, | ||
163 | const Evas_Object_Text *o, Evas_Coord cx, Evas_Coord cy) | ||
164 | { | ||
165 | Evas_Object_Text_Item *it; | ||
166 | |||
167 | #ifdef BIDI_SUPPORT | ||
168 | /*FIXME: not very efficient, sort the items arrays. */ | ||
169 | /* Reorder if it's a bidi text */ | ||
170 | if (o->bidi_par_props) | ||
171 | { | ||
172 | Eina_List *logical_it = NULL; | ||
173 | Evas_Object_Text_Item *i; | ||
174 | Eina_List *itr; | ||
175 | Evas_Coord x = 0; | ||
176 | /* Insert all to the logical list */ | ||
177 | EINA_INLIST_FOREACH(o->items, i) | ||
178 | { | ||
179 | logical_it = eina_list_sorted_insert(logical_it, | ||
180 | _evas_object_text_it_compare_logical, i); | ||
181 | } | ||
182 | EINA_LIST_FOREACH(logical_it, itr, it) | ||
183 | { | ||
184 | if ((x <= cx) && (cx < x + it->adv)) | ||
185 | { | ||
186 | return it->text_pos + ENFN->font_last_up_to_pos(ENDT, | ||
187 | o->font, | ||
188 | &it->text_props, | ||
189 | cx - x, | ||
190 | cy); | ||
191 | } | ||
192 | x += it->adv; | ||
193 | } | ||
194 | eina_list_free(logical_it); | ||
195 | } | ||
196 | else | ||
197 | #endif | ||
198 | { | ||
199 | EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it) | ||
200 | { | ||
201 | if ((it->x <= cx) && (cx < it->x + it->adv)) | ||
202 | { | ||
203 | return it->text_pos + ENFN->font_last_up_to_pos(ENDT, | ||
204 | o->font, | ||
205 | &it->text_props, | ||
206 | cx - it->x, | ||
207 | cy); | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | return -1; | ||
212 | } | ||
213 | |||
214 | static int | ||
215 | _evas_object_text_char_at_coords(const Evas_Object *obj, | ||
216 | const Evas_Object_Text *o, Evas_Coord cx, Evas_Coord cy, | ||
217 | Evas_Coord *rx, Evas_Coord *ry, Evas_Coord *rw, Evas_Coord *rh) | ||
218 | { | ||
219 | Evas_Object_Text_Item *it; | ||
220 | |||
221 | EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it) | ||
222 | { | ||
223 | if ((it->x <= cx) && (cx < it->x + it->adv)) | ||
224 | { | ||
225 | return it->text_pos + ENFN->font_char_at_coords_get(ENDT, | ||
226 | o->font, | ||
227 | &it->text_props, | ||
228 | cx - it->x, | ||
229 | cy, | ||
230 | rx, ry, | ||
231 | rw, rh); | ||
232 | } | ||
233 | } | ||
234 | return -1; | ||
235 | } | ||
236 | |||
237 | static Evas_Coord | ||
238 | _evas_object_text_horiz_advance_get(const Evas_Object *obj, | ||
239 | const Evas_Object_Text *o) | ||
240 | { | ||
241 | Evas_Object_Text_Item *it; | ||
242 | Evas_Coord adv; | ||
243 | (void) obj; | ||
244 | |||
245 | adv = 0; | ||
246 | EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it) | ||
247 | { | ||
248 | adv += it->adv; | ||
249 | } | ||
250 | return adv; | ||
251 | } | ||
252 | |||
253 | static Evas_Coord | ||
254 | _evas_object_text_vert_advance_get(const Evas_Object *obj __UNUSED__, | ||
255 | const Evas_Object_Text *o) | ||
256 | { | ||
257 | return o->max_ascent + o->max_descent; | ||
258 | } | ||
259 | |||
260 | EAPI Evas_Object * | ||
261 | evas_object_text_add(Evas *e) | ||
262 | { | ||
263 | Evas_Object *obj; | ||
264 | |||
265 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
266 | return NULL; | ||
267 | MAGIC_CHECK_END(); | ||
268 | obj = evas_object_new(e); | ||
269 | evas_object_text_init(obj); | ||
270 | evas_object_inject(obj, e); | ||
271 | return obj; | ||
272 | } | ||
273 | |||
274 | EAPI void | ||
275 | evas_object_text_font_source_set(Evas_Object *obj, const char *font_source) | ||
276 | { | ||
277 | Evas_Object_Text *o; | ||
278 | |||
279 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
280 | return; | ||
281 | MAGIC_CHECK_END(); | ||
282 | o = (Evas_Object_Text *)(obj->object_data); | ||
283 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
284 | return; | ||
285 | MAGIC_CHECK_END(); | ||
286 | |||
287 | if ((o->cur.source) && (font_source) && | ||
288 | (!strcmp(o->cur.source, font_source))) | ||
289 | return; | ||
290 | /* | ||
291 | if (o->cur.source) eina_stringshare_del(o->cur.source); | ||
292 | if (font_source) o->cur.source = eina_stringshare_add(font_source); | ||
293 | else o->cur.source = NULL; | ||
294 | */ | ||
295 | eina_stringshare_replace(&o->cur.source, font_source); | ||
296 | } | ||
297 | |||
298 | EAPI const char * | ||
299 | evas_object_text_font_source_get(const Evas_Object *obj) | ||
300 | { | ||
301 | Evas_Object_Text *o; | ||
302 | |||
303 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
304 | return NULL; | ||
305 | MAGIC_CHECK_END(); | ||
306 | o = (Evas_Object_Text *)(obj->object_data); | ||
307 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
308 | return NULL; | ||
309 | MAGIC_CHECK_END(); | ||
310 | return o->cur.source; | ||
311 | } | ||
312 | |||
313 | EAPI void | ||
314 | evas_object_text_font_set(Evas_Object *obj, const char *font, Evas_Font_Size size) | ||
315 | { | ||
316 | Evas_Object_Text *o; | ||
317 | int is, was = 0, pass = 0, freeze = 0; | ||
318 | Evas_Font_Description *fdesc; | ||
319 | |||
320 | if ((!font) || (size <= 0)) return; | ||
321 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
322 | return; | ||
323 | MAGIC_CHECK_END(); | ||
324 | o = (Evas_Object_Text *)(obj->object_data); | ||
325 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
326 | return; | ||
327 | MAGIC_CHECK_END(); | ||
328 | |||
329 | fdesc = evas_font_desc_new(); | ||
330 | evas_font_name_parse(fdesc, font); | ||
331 | if (o->cur.fdesc && !evas_font_desc_cmp(fdesc, o->cur.fdesc) && | ||
332 | (size == o->cur.size)) | ||
333 | { | ||
334 | evas_font_desc_unref(fdesc); | ||
335 | return; | ||
336 | } | ||
337 | |||
338 | if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc); | ||
339 | o->cur.fdesc = fdesc; | ||
340 | |||
341 | o->cur.size = size; | ||
342 | eina_stringshare_replace(&o->cur.font, font); | ||
343 | o->prev.font = NULL; | ||
344 | |||
345 | if (obj->layer->evas->events_frozen <= 0) | ||
346 | { | ||
347 | pass = evas_event_passes_through(obj); | ||
348 | freeze = evas_event_freezes_through(obj); | ||
349 | if ((!pass) && (!freeze)) | ||
350 | was = evas_object_is_in_output_rect(obj, | ||
351 | obj->layer->evas->pointer.x, | ||
352 | obj->layer->evas->pointer.y, 1, 1); | ||
353 | } | ||
354 | |||
355 | #ifdef EVAS_FRAME_QUEUING | ||
356 | if (o->font) | ||
357 | evas_common_pipe_op_text_flush((RGBA_Font *) o->font); | ||
358 | #endif | ||
359 | |||
360 | /* DO IT */ | ||
361 | if (o->font) | ||
362 | { | ||
363 | evas_font_free(obj->layer->evas, o->font); | ||
364 | o->font = NULL; | ||
365 | } | ||
366 | |||
367 | o->font = evas_font_load(obj->layer->evas, o->cur.fdesc, o->cur.source, | ||
368 | (int)(((double) o->cur.size) * obj->cur.scale)); | ||
369 | if (o->font) | ||
370 | { | ||
371 | o->ascent = ENFN->font_ascent_get(ENDT, o->font); | ||
372 | o->descent = ENFN->font_descent_get(ENDT, o->font); | ||
373 | o->max_ascent = ENFN->font_max_ascent_get(ENDT, o->font); | ||
374 | o->max_descent = ENFN->font_max_descent_get(ENDT, o->font); | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | o->ascent = 0; | ||
379 | o->descent = 0; | ||
380 | o->max_ascent = 0; | ||
381 | o->max_descent = 0; | ||
382 | } | ||
383 | _evas_object_text_recalc(obj); | ||
384 | o->changed = 1; | ||
385 | evas_object_change(obj); | ||
386 | evas_object_clip_dirty(obj); | ||
387 | evas_object_coords_recalc(obj); | ||
388 | if (obj->layer->evas->events_frozen <= 0) | ||
389 | { | ||
390 | if ((!pass) && (!freeze)) | ||
391 | { | ||
392 | is = evas_object_is_in_output_rect(obj, | ||
393 | obj->layer->evas->pointer.x, | ||
394 | obj->layer->evas->pointer.y, | ||
395 | 1, 1); | ||
396 | if ((is ^ was) && obj->cur.visible) | ||
397 | evas_event_feed_mouse_move(obj->layer->evas, | ||
398 | obj->layer->evas->pointer.x, | ||
399 | obj->layer->evas->pointer.y, | ||
400 | obj->layer->evas->last_timestamp, | ||
401 | NULL); | ||
402 | } | ||
403 | } | ||
404 | evas_object_inform_call_resize(obj); | ||
405 | } | ||
406 | |||
407 | EAPI void | ||
408 | evas_object_text_font_get(const Evas_Object *obj, const char **font, Evas_Font_Size *size) | ||
409 | { | ||
410 | Evas_Object_Text *o; | ||
411 | |||
412 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
413 | if (font) *font = ""; | ||
414 | if (size) *size = 0; | ||
415 | return; | ||
416 | MAGIC_CHECK_END(); | ||
417 | o = (Evas_Object_Text *)(obj->object_data); | ||
418 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
419 | if (font) *font = ""; | ||
420 | if (size) *size = 0; | ||
421 | return; | ||
422 | MAGIC_CHECK_END(); | ||
423 | if (font) *font = o->cur.font; | ||
424 | if (size) *size = o->cur.size; | ||
425 | } | ||
426 | |||
427 | |||
428 | /** | ||
429 | * @internal | ||
430 | * Create a new text layout item from the string and the format. | ||
431 | * | ||
432 | * @param c the context to work on - Not NULL. | ||
433 | * @param fmt the format to use. | ||
434 | * @param str the string to use. | ||
435 | */ | ||
436 | static Evas_Object_Text_Item * | ||
437 | _evas_object_text_item_new(Evas_Object *obj, Evas_Object_Text *o, | ||
438 | Evas_Font_Instance *fi, const Eina_Unicode *str, Evas_Script_Type script, | ||
439 | size_t pos, size_t visual_pos, size_t len) | ||
440 | { | ||
441 | Evas_Object_Text_Item *it; | ||
442 | |||
443 | it = calloc(1, sizeof(Evas_Object_Text_Item)); | ||
444 | it->text_pos = pos; | ||
445 | it->visual_pos = visual_pos; | ||
446 | evas_common_text_props_bidi_set(&it->text_props, o->bidi_par_props, | ||
447 | it->text_pos); | ||
448 | evas_common_text_props_script_set(&it->text_props, script); | ||
449 | |||
450 | if (fi) | ||
451 | { | ||
452 | ENFN->font_text_props_info_create(ENDT, | ||
453 | fi, str + pos, &it->text_props, | ||
454 | o->bidi_par_props, it->text_pos, len); | ||
455 | |||
456 | ENFN->font_string_size_get(ENDT, | ||
457 | o->font, | ||
458 | &it->text_props, | ||
459 | &it->w, &it->h); | ||
460 | it->adv = ENFN->font_h_advance_get(ENDT, o->font, | ||
461 | &it->text_props); | ||
462 | } | ||
463 | o->items = (Evas_Object_Text_Item *) | ||
464 | eina_inlist_append(EINA_INLIST_GET(o->items), EINA_INLIST_GET(it)); | ||
465 | return it; | ||
466 | } | ||
467 | |||
468 | /** | ||
469 | * @internal | ||
470 | * Orders o->items according to the visual position. | ||
471 | * | ||
472 | * @param obj the evas object | ||
473 | * @param o the text object | ||
474 | */ | ||
475 | static void | ||
476 | _evas_object_text_item_order(Evas_Object *obj, Evas_Object_Text *o) | ||
477 | { | ||
478 | (void) obj; | ||
479 | #ifdef BIDI_SUPPORT | ||
480 | /*FIXME: not very efficient, sort the items arrays. */ | ||
481 | /* Reorder if it's a bidi text */ | ||
482 | if (o->bidi_par_props) | ||
483 | { | ||
484 | Evas_Object_Text_Item *i, *j, *min; | ||
485 | i = o->items; | ||
486 | while (i) | ||
487 | { | ||
488 | min = i; | ||
489 | EINA_INLIST_FOREACH(i, j) | ||
490 | { | ||
491 | if (j->visual_pos < min->visual_pos) | ||
492 | { | ||
493 | min = j; | ||
494 | } | ||
495 | } | ||
496 | if (min != i) | ||
497 | { | ||
498 | o->items = (Evas_Object_Text_Item *) eina_inlist_remove(EINA_INLIST_GET(o->items), EINA_INLIST_GET(min)); | ||
499 | o->items = (Evas_Object_Text_Item *) eina_inlist_prepend_relative(EINA_INLIST_GET(o->items), EINA_INLIST_GET(min), EINA_INLIST_GET(i)); | ||
500 | } | ||
501 | |||
502 | i = (Evas_Object_Text_Item *) EINA_INLIST_GET(min)->next; | ||
503 | } | ||
504 | } | ||
505 | #endif | ||
506 | |||
507 | /* calculate the positions according to the order. */ | ||
508 | { | ||
509 | Evas_Object_Text_Item *it = o->items; | ||
510 | Evas_Coord x = 0; | ||
511 | |||
512 | while (it) | ||
513 | { | ||
514 | it->x = x; | ||
515 | x += it->adv; | ||
516 | it = (Evas_Object_Text_Item *) EINA_INLIST_GET(it)->next; | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * @internal | ||
523 | * Populates o->items with the items of the text according to text | ||
524 | * | ||
525 | * @param obj the evas object | ||
526 | * @param o the text object | ||
527 | * @param text the text to layout | ||
528 | */ | ||
529 | static void | ||
530 | _evas_object_text_layout(Evas_Object *obj, Evas_Object_Text *o, const Eina_Unicode *text) | ||
531 | { | ||
532 | EvasBiDiStrIndex *v_to_l = NULL; | ||
533 | size_t pos, visual_pos; | ||
534 | int len = eina_unicode_strlen(text), par_len; | ||
535 | #ifdef BIDI_SUPPORT | ||
536 | int *segment_idxs = NULL; | ||
537 | if (o->bidi_delimiters) | ||
538 | segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters); | ||
539 | evas_bidi_paragraph_props_unref(o->bidi_par_props); | ||
540 | o->bidi_par_props = evas_bidi_paragraph_props_get(text, len, segment_idxs); | ||
541 | evas_bidi_props_reorder_line(NULL, 0, len, o->bidi_par_props, &v_to_l); | ||
542 | if (segment_idxs) free(segment_idxs); | ||
543 | #endif | ||
544 | visual_pos = pos = 0; | ||
545 | |||
546 | par_len = len; | ||
547 | while (len > 0) | ||
548 | { | ||
549 | Evas_Font_Instance *script_fi = NULL; | ||
550 | int script_len = len, tmp_cut; | ||
551 | Evas_Script_Type script; | ||
552 | tmp_cut = evas_common_language_script_end_of_run_get( | ||
553 | text + pos, | ||
554 | o->bidi_par_props, | ||
555 | pos, len); | ||
556 | if (tmp_cut > 0) | ||
557 | script_len = tmp_cut; | ||
558 | |||
559 | script = evas_common_language_script_type_get(text, script_len); | ||
560 | |||
561 | while (script_len > 0) | ||
562 | { | ||
563 | Evas_Font_Instance *cur_fi = NULL; | ||
564 | int run_len = script_len; | ||
565 | if (o->font) | ||
566 | { | ||
567 | run_len = ENFN->font_run_end_get(ENDT, | ||
568 | o->font, &script_fi, &cur_fi, | ||
569 | script, text + pos, script_len); | ||
570 | } | ||
571 | #ifdef BIDI_SUPPORT | ||
572 | visual_pos = evas_bidi_position_logical_to_visual( | ||
573 | v_to_l, par_len, pos); | ||
574 | #else | ||
575 | visual_pos = pos; | ||
576 | #endif | ||
577 | _evas_object_text_item_new(obj, o, cur_fi, text, script, | ||
578 | pos, visual_pos, run_len); | ||
579 | |||
580 | pos += run_len; | ||
581 | script_len -= run_len; | ||
582 | len -= run_len; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | _evas_object_text_item_order(obj, o); | ||
587 | |||
588 | if (v_to_l) free(v_to_l); | ||
589 | } | ||
590 | |||
591 | |||
592 | EAPI void | ||
593 | evas_object_text_text_set(Evas_Object *obj, const char *_text) | ||
594 | { | ||
595 | Evas_Object_Text *o; | ||
596 | int is, was, len; | ||
597 | Eina_Unicode *text; | ||
598 | |||
599 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
600 | return; | ||
601 | MAGIC_CHECK_END(); | ||
602 | o = (Evas_Object_Text *)(obj->object_data); | ||
603 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
604 | return; | ||
605 | MAGIC_CHECK_END(); | ||
606 | |||
607 | if ((o->cur.utf8_text) && (_text) && (!strcmp(o->cur.utf8_text, _text))) | ||
608 | return; | ||
609 | text = eina_unicode_utf8_to_unicode(_text, &len); | ||
610 | |||
611 | if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING); | ||
612 | was = evas_object_is_in_output_rect(obj, | ||
613 | obj->layer->evas->pointer.x, | ||
614 | obj->layer->evas->pointer.y, 1, 1); | ||
615 | /* DO II */ | ||
616 | /*Update bidi_props*/ | ||
617 | |||
618 | if (o->items) _evas_object_text_items_clear(o); | ||
619 | |||
620 | if ((text) && (*text)) | ||
621 | { | ||
622 | _evas_object_text_layout(obj, o, text); | ||
623 | eina_stringshare_replace(&o->cur.utf8_text, _text); | ||
624 | o->prev.utf8_text = NULL; | ||
625 | } | ||
626 | else | ||
627 | { | ||
628 | eina_stringshare_replace(&o->cur.utf8_text, NULL); | ||
629 | } | ||
630 | if (text) | ||
631 | { | ||
632 | free(text); | ||
633 | text = NULL; | ||
634 | } | ||
635 | _evas_object_text_recalc(obj); | ||
636 | o->changed = 1; | ||
637 | evas_object_change(obj); | ||
638 | evas_object_clip_dirty(obj); | ||
639 | evas_object_coords_recalc(obj); | ||
640 | is = evas_object_is_in_output_rect(obj, | ||
641 | obj->layer->evas->pointer.x, | ||
642 | obj->layer->evas->pointer.y, 1, 1); | ||
643 | if ((is || was) && obj->cur.visible) | ||
644 | evas_event_feed_mouse_move(obj->layer->evas, | ||
645 | obj->layer->evas->pointer.x, | ||
646 | obj->layer->evas->pointer.y, | ||
647 | obj->layer->evas->last_timestamp, | ||
648 | NULL); | ||
649 | evas_object_inform_call_resize(obj); | ||
650 | if (text) free(text); | ||
651 | } | ||
652 | |||
653 | EAPI void | ||
654 | evas_object_text_bidi_delimiters_set(Evas_Object *obj, const char *delim) | ||
655 | { | ||
656 | Evas_Object_Text *o; | ||
657 | |||
658 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
659 | return; | ||
660 | MAGIC_CHECK_END(); | ||
661 | o = (Evas_Object_Text *)(obj->object_data); | ||
662 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
663 | return; | ||
664 | MAGIC_CHECK_END(); | ||
665 | |||
666 | eina_stringshare_replace(&o->bidi_delimiters, delim); | ||
667 | } | ||
668 | |||
669 | EAPI const char * | ||
670 | evas_object_text_bidi_delimiters_get(const Evas_Object *obj) | ||
671 | { | ||
672 | Evas_Object_Text *o; | ||
673 | |||
674 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
675 | return NULL; | ||
676 | MAGIC_CHECK_END(); | ||
677 | o = (Evas_Object_Text *)(obj->object_data); | ||
678 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
679 | return NULL; | ||
680 | MAGIC_CHECK_END(); | ||
681 | |||
682 | return o->bidi_delimiters; | ||
683 | } | ||
684 | |||
685 | |||
686 | EAPI const char * | ||
687 | evas_object_text_text_get(const Evas_Object *obj) | ||
688 | { | ||
689 | Evas_Object_Text *o; | ||
690 | |||
691 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
692 | return NULL; | ||
693 | MAGIC_CHECK_END(); | ||
694 | o = (Evas_Object_Text *)(obj->object_data); | ||
695 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
696 | return NULL; | ||
697 | MAGIC_CHECK_END(); | ||
698 | return o->cur.utf8_text; | ||
699 | } | ||
700 | |||
701 | EAPI Evas_BiDi_Direction | ||
702 | evas_object_text_direction_get(const Evas_Object *obj) | ||
703 | { | ||
704 | Evas_Object_Text *o; | ||
705 | |||
706 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
707 | return EVAS_BIDI_DIRECTION_NEUTRAL; | ||
708 | MAGIC_CHECK_END(); | ||
709 | o = (Evas_Object_Text *)(obj->object_data); | ||
710 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
711 | return EVAS_BIDI_DIRECTION_NEUTRAL; | ||
712 | MAGIC_CHECK_END(); | ||
713 | if (o->items) | ||
714 | { | ||
715 | return o->items->text_props.bidi.dir; | ||
716 | } | ||
717 | return EVAS_BIDI_DIRECTION_NEUTRAL; | ||
718 | } | ||
719 | |||
720 | EAPI Evas_Coord | ||
721 | evas_object_text_ascent_get(const Evas_Object *obj) | ||
722 | { | ||
723 | Evas_Object_Text *o; | ||
724 | |||
725 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
726 | return 0; | ||
727 | MAGIC_CHECK_END(); | ||
728 | o = (Evas_Object_Text *)(obj->object_data); | ||
729 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
730 | return 0; | ||
731 | MAGIC_CHECK_END(); | ||
732 | return o->ascent; | ||
733 | } | ||
734 | |||
735 | EAPI Evas_Coord | ||
736 | evas_object_text_descent_get(const Evas_Object *obj) | ||
737 | { | ||
738 | Evas_Object_Text *o; | ||
739 | |||
740 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
741 | return 0; | ||
742 | MAGIC_CHECK_END(); | ||
743 | o = (Evas_Object_Text *)(obj->object_data); | ||
744 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
745 | return 0; | ||
746 | MAGIC_CHECK_END(); | ||
747 | return o->descent; | ||
748 | } | ||
749 | |||
750 | EAPI Evas_Coord | ||
751 | evas_object_text_max_ascent_get(const Evas_Object *obj) | ||
752 | { | ||
753 | Evas_Object_Text *o; | ||
754 | |||
755 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
756 | return 0; | ||
757 | MAGIC_CHECK_END(); | ||
758 | o = (Evas_Object_Text *)(obj->object_data); | ||
759 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
760 | return 0; | ||
761 | MAGIC_CHECK_END(); | ||
762 | return o->max_ascent; | ||
763 | } | ||
764 | |||
765 | EAPI Evas_Coord | ||
766 | evas_object_text_max_descent_get(const Evas_Object *obj) | ||
767 | { | ||
768 | Evas_Object_Text *o; | ||
769 | |||
770 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
771 | return 0; | ||
772 | MAGIC_CHECK_END(); | ||
773 | o = (Evas_Object_Text *)(obj->object_data); | ||
774 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
775 | return 0; | ||
776 | MAGIC_CHECK_END(); | ||
777 | return o->max_descent; | ||
778 | } | ||
779 | |||
780 | EAPI Evas_Coord | ||
781 | evas_object_text_inset_get(const Evas_Object *obj) | ||
782 | { | ||
783 | Evas_Object_Text *o; | ||
784 | |||
785 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
786 | return 0; | ||
787 | MAGIC_CHECK_END(); | ||
788 | o = (Evas_Object_Text *)(obj->object_data); | ||
789 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
790 | return 0; | ||
791 | MAGIC_CHECK_END(); | ||
792 | if (!o->font) return 0; | ||
793 | if (!o->items) return 0; | ||
794 | return ENFN->font_inset_get(ENDT, o->font, &o->items->text_props); | ||
795 | } | ||
796 | |||
797 | EAPI Evas_Coord | ||
798 | evas_object_text_horiz_advance_get(const Evas_Object *obj) | ||
799 | { | ||
800 | Evas_Object_Text *o; | ||
801 | |||
802 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
803 | return 0; | ||
804 | MAGIC_CHECK_END(); | ||
805 | o = (Evas_Object_Text *)(obj->object_data); | ||
806 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
807 | return 0; | ||
808 | MAGIC_CHECK_END(); | ||
809 | if (!o->font) return 0; | ||
810 | if (!o->items) return 0; | ||
811 | return _evas_object_text_horiz_advance_get(obj, o); | ||
812 | } | ||
813 | |||
814 | EAPI Evas_Coord | ||
815 | evas_object_text_vert_advance_get(const Evas_Object *obj) | ||
816 | { | ||
817 | Evas_Object_Text *o; | ||
818 | |||
819 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
820 | return 0; | ||
821 | MAGIC_CHECK_END(); | ||
822 | o = (Evas_Object_Text *)(obj->object_data); | ||
823 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
824 | return 0; | ||
825 | MAGIC_CHECK_END(); | ||
826 | if (!o->font) return 0; | ||
827 | if (!o->items) return o->ascent + o->descent; | ||
828 | return _evas_object_text_vert_advance_get(obj, o); | ||
829 | } | ||
830 | |||
831 | EAPI Eina_Bool | ||
832 | evas_object_text_char_pos_get(const Evas_Object *obj, int pos, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) | ||
833 | { | ||
834 | Evas_Object_Text *o; | ||
835 | int l = 0, r = 0, t = 0, b = 0; | ||
836 | int ret, x = 0, y = 0, w = 0, h = 0; | ||
837 | |||
838 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
839 | return EINA_FALSE; | ||
840 | MAGIC_CHECK_END(); | ||
841 | o = (Evas_Object_Text *)(obj->object_data); | ||
842 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
843 | return EINA_FALSE; | ||
844 | MAGIC_CHECK_END(); | ||
845 | if (!o->font) return EINA_FALSE; | ||
846 | if (!o->items || (pos < 0)) return EINA_FALSE; | ||
847 | ret = _evas_object_text_char_coords_get(obj, o, (size_t) pos, | ||
848 | &x, &y, &w, &h); | ||
849 | evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b); | ||
850 | y += o->max_ascent - t; | ||
851 | x -= l; | ||
852 | if (x < 0) | ||
853 | { | ||
854 | w += x; | ||
855 | x = 0; | ||
856 | } | ||
857 | if ((x + w) > obj->cur.geometry.w) w = obj->cur.geometry.w - x; | ||
858 | if (w < 0) w = 0; | ||
859 | if (y < 0) | ||
860 | { | ||
861 | h += y; | ||
862 | y = 0; | ||
863 | } | ||
864 | if ((y + h) > obj->cur.geometry.h) h = obj->cur.geometry.h - y; | ||
865 | if (h < 0) h = 0; | ||
866 | if (cx) *cx = x; | ||
867 | if (cy) *cy = y; | ||
868 | if (cw) *cw = w + l + r; | ||
869 | if (ch) *ch = h + t + b; | ||
870 | return ret; | ||
871 | } | ||
872 | |||
873 | |||
874 | EAPI int | ||
875 | evas_object_text_last_up_to_pos(const Evas_Object *obj, Evas_Coord x, Evas_Coord y) | ||
876 | { | ||
877 | Evas_Object_Text *o; | ||
878 | |||
879 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
880 | return -1; | ||
881 | MAGIC_CHECK_END(); | ||
882 | o = (Evas_Object_Text *)(obj->object_data); | ||
883 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
884 | return -1; | ||
885 | MAGIC_CHECK_END(); | ||
886 | if (!o->font) return -1; | ||
887 | if (!o->items) return -1; | ||
888 | return _evas_object_text_last_up_to_pos(obj, o, x, y - o->max_ascent); | ||
889 | } | ||
890 | |||
891 | EAPI int | ||
892 | evas_object_text_char_coords_get(const Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) | ||
893 | { | ||
894 | Evas_Object_Text *o; | ||
895 | int l = 0, r = 0, t = 0, b = 0; | ||
896 | int ret, rx = 0, ry = 0, rw = 0, rh = 0; | ||
897 | |||
898 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
899 | return -1; | ||
900 | MAGIC_CHECK_END(); | ||
901 | o = (Evas_Object_Text *)(obj->object_data); | ||
902 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
903 | return -1; | ||
904 | MAGIC_CHECK_END(); | ||
905 | if (!o->font) return -1; | ||
906 | if (!o->items) return -1; | ||
907 | ret = _evas_object_text_char_at_coords(obj, o, x, y - o->max_ascent, | ||
908 | &rx, &ry, &rw, &rh); | ||
909 | evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b); | ||
910 | ry += o->max_ascent - t; | ||
911 | rx -= l; | ||
912 | if (rx < 0) | ||
913 | { | ||
914 | rw += rx; | ||
915 | rx = 0; | ||
916 | } | ||
917 | if ((rx + rw) > obj->cur.geometry.w) rw = obj->cur.geometry.w - rx; | ||
918 | if (rw < 0) rw = 0; | ||
919 | if (ry < 0) | ||
920 | { | ||
921 | rh += ry; | ||
922 | ry = 0; | ||
923 | } | ||
924 | if ((ry + rh) > obj->cur.geometry.h) rh = obj->cur.geometry.h - ry; | ||
925 | if (rh < 0) rh = 0; | ||
926 | if (cx) *cx = rx; | ||
927 | if (cy) *cy = ry; | ||
928 | if (cw) *cw = rw + l + r; | ||
929 | if (ch) *ch = rh + t + b; | ||
930 | return ret; | ||
931 | } | ||
932 | |||
933 | EAPI void | ||
934 | evas_object_text_style_set(Evas_Object *obj, Evas_Text_Style_Type style) | ||
935 | { | ||
936 | Evas_Object_Text *o; | ||
937 | int pl = 0, pr = 0, pt = 0, pb = 0, l = 0, r = 0, t = 0, b = 0; | ||
938 | |||
939 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
940 | return; | ||
941 | MAGIC_CHECK_END(); | ||
942 | o = (Evas_Object_Text *)(obj->object_data); | ||
943 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
944 | return; | ||
945 | MAGIC_CHECK_END(); | ||
946 | if (o->cur.style == style) return; | ||
947 | evas_text_style_pad_get(o->cur.style, &pl, &pr, &pt, &pb); | ||
948 | o->cur.style = style; | ||
949 | evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b); | ||
950 | if (o->items) | ||
951 | obj->cur.geometry.w += (l - pl) + (r - pr); | ||
952 | else | ||
953 | obj->cur.geometry.w = 0; | ||
954 | obj->cur.geometry.h += (t - pt) + (b - pb); | ||
955 | evas_object_change(obj); | ||
956 | evas_object_clip_dirty(obj); | ||
957 | } | ||
958 | |||
959 | EAPI Evas_Text_Style_Type | ||
960 | evas_object_text_style_get(const Evas_Object *obj) | ||
961 | { | ||
962 | Evas_Object_Text *o; | ||
963 | |||
964 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
965 | return EVAS_TEXT_STYLE_PLAIN; | ||
966 | MAGIC_CHECK_END(); | ||
967 | o = (Evas_Object_Text *)(obj->object_data); | ||
968 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
969 | return EVAS_TEXT_STYLE_PLAIN; | ||
970 | MAGIC_CHECK_END(); | ||
971 | return o->cur.style; | ||
972 | } | ||
973 | |||
974 | EAPI void | ||
975 | evas_object_text_shadow_color_set(Evas_Object *obj, int r, int g, int b, int a) | ||
976 | { | ||
977 | Evas_Object_Text *o; | ||
978 | |||
979 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
980 | return; | ||
981 | MAGIC_CHECK_END(); | ||
982 | o = (Evas_Object_Text *)(obj->object_data); | ||
983 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
984 | return; | ||
985 | MAGIC_CHECK_END(); | ||
986 | if ((o->cur.shadow.r == r) && (o->cur.shadow.g == g) && | ||
987 | (o->cur.shadow.b == b) && (o->cur.shadow.a == a)) | ||
988 | return; | ||
989 | o->cur.shadow.r = r; | ||
990 | o->cur.shadow.g = g; | ||
991 | o->cur.shadow.b = b; | ||
992 | o->cur.shadow.a = a; | ||
993 | o->changed = 1; | ||
994 | evas_object_change(obj); | ||
995 | } | ||
996 | |||
997 | EAPI void | ||
998 | evas_object_text_shadow_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a) | ||
999 | { | ||
1000 | Evas_Object_Text *o; | ||
1001 | |||
1002 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1003 | if (r) *r = 0; | ||
1004 | if (g) *g = 0; | ||
1005 | if (b) *b = 0; | ||
1006 | if (a) *a = 0; | ||
1007 | return; | ||
1008 | MAGIC_CHECK_END(); | ||
1009 | o = (Evas_Object_Text *)(obj->object_data); | ||
1010 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1011 | if (r) *r = 0; | ||
1012 | if (g) *g = 0; | ||
1013 | if (b) *b = 0; | ||
1014 | if (a) *a = 0; | ||
1015 | return; | ||
1016 | MAGIC_CHECK_END(); | ||
1017 | if (r) *r = o->cur.shadow.r; | ||
1018 | if (g) *g = o->cur.shadow.g; | ||
1019 | if (b) *b = o->cur.shadow.b; | ||
1020 | if (a) *a = o->cur.shadow.a; | ||
1021 | } | ||
1022 | |||
1023 | EAPI void | ||
1024 | evas_object_text_glow_color_set(Evas_Object *obj, int r, int g, int b, int a) | ||
1025 | { | ||
1026 | Evas_Object_Text *o; | ||
1027 | |||
1028 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1029 | return; | ||
1030 | MAGIC_CHECK_END(); | ||
1031 | o = (Evas_Object_Text *)(obj->object_data); | ||
1032 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1033 | return; | ||
1034 | MAGIC_CHECK_END(); | ||
1035 | if ((o->cur.glow.r == r) && (o->cur.glow.g == g) && | ||
1036 | (o->cur.glow.b == b) && (o->cur.glow.a == a)) | ||
1037 | return; | ||
1038 | o->cur.glow.r = r; | ||
1039 | o->cur.glow.g = g; | ||
1040 | o->cur.glow.b = b; | ||
1041 | o->cur.glow.a = a; | ||
1042 | o->changed = 1; | ||
1043 | evas_object_change(obj); | ||
1044 | } | ||
1045 | |||
1046 | EAPI void | ||
1047 | evas_object_text_glow_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a) | ||
1048 | { | ||
1049 | Evas_Object_Text *o; | ||
1050 | |||
1051 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1052 | if (r) *r = 0; | ||
1053 | if (g) *g = 0; | ||
1054 | if (b) *b = 0; | ||
1055 | if (a) *a = 0; | ||
1056 | return; | ||
1057 | MAGIC_CHECK_END(); | ||
1058 | o = (Evas_Object_Text *)(obj->object_data); | ||
1059 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1060 | if (r) *r = 0; | ||
1061 | if (g) *g = 0; | ||
1062 | if (b) *b = 0; | ||
1063 | if (a) *a = 0; | ||
1064 | return; | ||
1065 | MAGIC_CHECK_END(); | ||
1066 | if (r) *r = o->cur.glow.r; | ||
1067 | if (g) *g = o->cur.glow.g; | ||
1068 | if (b) *b = o->cur.glow.b; | ||
1069 | if (a) *a = o->cur.glow.a; | ||
1070 | } | ||
1071 | |||
1072 | EAPI void | ||
1073 | evas_object_text_glow2_color_set(Evas_Object *obj, int r, int g, int b, int a) | ||
1074 | { | ||
1075 | Evas_Object_Text *o; | ||
1076 | |||
1077 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1078 | return; | ||
1079 | MAGIC_CHECK_END(); | ||
1080 | o = (Evas_Object_Text *)(obj->object_data); | ||
1081 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1082 | return; | ||
1083 | MAGIC_CHECK_END(); | ||
1084 | if ((o->cur.glow2.r == r) && (o->cur.glow2.g == g) && | ||
1085 | (o->cur.glow2.b == b) && (o->cur.glow2.a == a)) | ||
1086 | return; | ||
1087 | o->cur.glow2.r = r; | ||
1088 | o->cur.glow2.g = g; | ||
1089 | o->cur.glow2.b = b; | ||
1090 | o->cur.glow2.a = a; | ||
1091 | o->changed = 1; | ||
1092 | evas_object_change(obj); | ||
1093 | } | ||
1094 | |||
1095 | EAPI void | ||
1096 | evas_object_text_glow2_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a) | ||
1097 | { | ||
1098 | Evas_Object_Text *o; | ||
1099 | |||
1100 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1101 | if (r) *r = 0; | ||
1102 | if (g) *g = 0; | ||
1103 | if (b) *b = 0; | ||
1104 | if (a) *a = 0; | ||
1105 | return; | ||
1106 | MAGIC_CHECK_END(); | ||
1107 | o = (Evas_Object_Text *)(obj->object_data); | ||
1108 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1109 | if (r) *r = 0; | ||
1110 | if (g) *g = 0; | ||
1111 | if (b) *b = 0; | ||
1112 | if (a) *a = 0; | ||
1113 | return; | ||
1114 | MAGIC_CHECK_END(); | ||
1115 | if (r) *r = o->cur.glow2.r; | ||
1116 | if (g) *g = o->cur.glow2.g; | ||
1117 | if (b) *b = o->cur.glow2.b; | ||
1118 | if (a) *a = o->cur.glow2.a; | ||
1119 | } | ||
1120 | |||
1121 | EAPI void | ||
1122 | evas_object_text_outline_color_set(Evas_Object *obj, int r, int g, int b, int a) | ||
1123 | { | ||
1124 | Evas_Object_Text *o; | ||
1125 | |||
1126 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1127 | return; | ||
1128 | MAGIC_CHECK_END(); | ||
1129 | o = (Evas_Object_Text *)(obj->object_data); | ||
1130 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1131 | return; | ||
1132 | MAGIC_CHECK_END(); | ||
1133 | if ((o->cur.outline.r == r) && (o->cur.outline.g == g) && | ||
1134 | (o->cur.outline.b == b) && (o->cur.outline.a == a)) | ||
1135 | return; | ||
1136 | o->cur.outline.r = r; | ||
1137 | o->cur.outline.g = g; | ||
1138 | o->cur.outline.b = b; | ||
1139 | o->cur.outline.a = a; | ||
1140 | o->changed = 1; | ||
1141 | evas_object_change(obj); | ||
1142 | } | ||
1143 | |||
1144 | EAPI void | ||
1145 | evas_object_text_outline_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a) | ||
1146 | { | ||
1147 | Evas_Object_Text *o; | ||
1148 | |||
1149 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1150 | if (r) *r = 0; | ||
1151 | if (g) *g = 0; | ||
1152 | if (b) *b = 0; | ||
1153 | if (a) *a = 0; | ||
1154 | return; | ||
1155 | MAGIC_CHECK_END(); | ||
1156 | o = (Evas_Object_Text *)(obj->object_data); | ||
1157 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1158 | if (r) *r = 0; | ||
1159 | if (g) *g = 0; | ||
1160 | if (b) *b = 0; | ||
1161 | if (a) *a = 0; | ||
1162 | return; | ||
1163 | MAGIC_CHECK_END(); | ||
1164 | if (r) *r = o->cur.outline.r; | ||
1165 | if (g) *g = o->cur.outline.g; | ||
1166 | if (b) *b = o->cur.outline.b; | ||
1167 | if (a) *a = o->cur.outline.a; | ||
1168 | } | ||
1169 | |||
1170 | EAPI void | ||
1171 | evas_object_text_style_pad_get(const Evas_Object *obj, int *l, int *r, int *t, int *b) | ||
1172 | { | ||
1173 | int sl = 0, sr = 0, st = 0, sb = 0; | ||
1174 | Evas_Object_Text *o; | ||
1175 | |||
1176 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1177 | if (l) *l = 0; | ||
1178 | if (r) *r = 0; | ||
1179 | if (t) *t = 0; | ||
1180 | if (b) *b = 0; | ||
1181 | return; | ||
1182 | MAGIC_CHECK_END(); | ||
1183 | o = (Evas_Object_Text *)(obj->object_data); | ||
1184 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1185 | if (l) *l = 0; | ||
1186 | if (r) *r = 0; | ||
1187 | if (t) *t = 0; | ||
1188 | if (b) *b = 0; | ||
1189 | return; | ||
1190 | MAGIC_CHECK_END(); | ||
1191 | /* use temps to be certain we have initialized values */ | ||
1192 | evas_text_style_pad_get(o->cur.style, &sl, &sr, &st, &sb); | ||
1193 | if (l) *l = sl; | ||
1194 | if (r) *r = sr; | ||
1195 | if (t) *t = st; | ||
1196 | if (b) *b = sb; | ||
1197 | } | ||
1198 | |||
1199 | |||
1200 | |||
1201 | |||
1202 | EAPI int | ||
1203 | evas_string_char_next_get(const char *str, int pos, int *decoded) | ||
1204 | { | ||
1205 | int p, d; | ||
1206 | |||
1207 | if (decoded) *decoded = 0; | ||
1208 | if ((!str) || (pos < 0)) return 0; | ||
1209 | p = pos; | ||
1210 | d = eina_unicode_utf8_get_next(str, &p); | ||
1211 | if (decoded) *decoded = d; | ||
1212 | return p; | ||
1213 | } | ||
1214 | |||
1215 | EAPI int | ||
1216 | evas_string_char_prev_get(const char *str, int pos, int *decoded) | ||
1217 | { | ||
1218 | int p, d; | ||
1219 | |||
1220 | if (decoded) *decoded = 0; | ||
1221 | if ((!str) || (pos < 1)) return 0; | ||
1222 | p = pos; | ||
1223 | d = eina_unicode_utf8_get_prev(str, &p); | ||
1224 | if (decoded) *decoded = d; | ||
1225 | return p; | ||
1226 | } | ||
1227 | |||
1228 | EAPI int | ||
1229 | evas_string_char_len_get(const char *str) | ||
1230 | { | ||
1231 | if (!str) return 0; | ||
1232 | return eina_unicode_utf8_get_len(str); | ||
1233 | } | ||
1234 | |||
1235 | void | ||
1236 | evas_text_style_pad_get(Evas_Text_Style_Type style, int *l, int *r, int *t, int *b) | ||
1237 | { | ||
1238 | int sl = 0, sr = 0, st = 0, sb = 0; | ||
1239 | |||
1240 | /* Don't calc anything if there's no style. */ | ||
1241 | if (style != EVAS_TEXT_STYLE_PLAIN) | ||
1242 | { | ||
1243 | int shad_sz = 0, shad_dst = 0, out_sz = 0; | ||
1244 | int dx = 0, minx = 0, maxx = 0; | ||
1245 | int dy = 0, miny = 0, maxy = 0; | ||
1246 | Eina_Bool have_shadow = EINA_FALSE; | ||
1247 | |||
1248 | switch (style & EVAS_TEXT_STYLE_MASK_BASIC) | ||
1249 | { | ||
1250 | case EVAS_TEXT_STYLE_SHADOW: | ||
1251 | shad_dst = 1; | ||
1252 | have_shadow = EINA_TRUE; | ||
1253 | break; | ||
1254 | case EVAS_TEXT_STYLE_OUTLINE_SHADOW: | ||
1255 | case EVAS_TEXT_STYLE_FAR_SHADOW: | ||
1256 | shad_dst = 2; | ||
1257 | out_sz = 1; | ||
1258 | have_shadow = EINA_TRUE; | ||
1259 | break; | ||
1260 | case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW: | ||
1261 | shad_dst = 1; | ||
1262 | shad_sz = 2; | ||
1263 | out_sz = 1; | ||
1264 | have_shadow = EINA_TRUE; | ||
1265 | break; | ||
1266 | case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW: | ||
1267 | shad_dst = 2; | ||
1268 | shad_sz = 2; | ||
1269 | have_shadow = EINA_TRUE; | ||
1270 | break; | ||
1271 | case EVAS_TEXT_STYLE_SOFT_SHADOW: | ||
1272 | shad_dst = 1; | ||
1273 | shad_sz = 2; | ||
1274 | have_shadow = EINA_TRUE; | ||
1275 | break; | ||
1276 | case EVAS_TEXT_STYLE_GLOW: | ||
1277 | case EVAS_TEXT_STYLE_SOFT_OUTLINE: | ||
1278 | out_sz = 2; | ||
1279 | break; | ||
1280 | case EVAS_TEXT_STYLE_OUTLINE: | ||
1281 | out_sz = 1; | ||
1282 | break; | ||
1283 | default: | ||
1284 | break; | ||
1285 | } | ||
1286 | |||
1287 | minx = -out_sz; | ||
1288 | maxx = out_sz; | ||
1289 | miny = -out_sz; | ||
1290 | maxy = out_sz; | ||
1291 | if (have_shadow) | ||
1292 | { | ||
1293 | int shx1, shx2, shy1, shy2; | ||
1294 | switch (style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION) | ||
1295 | { | ||
1296 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT: | ||
1297 | dx = 1; | ||
1298 | dy = 1; | ||
1299 | break; | ||
1300 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM: | ||
1301 | dx = 0; | ||
1302 | dy = 1; | ||
1303 | break; | ||
1304 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT: | ||
1305 | dx = -1; | ||
1306 | dy = 1; | ||
1307 | break; | ||
1308 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT: | ||
1309 | dx = -1; | ||
1310 | dy = 0; | ||
1311 | break; | ||
1312 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT: | ||
1313 | dx = -1; | ||
1314 | dy = -1; | ||
1315 | break; | ||
1316 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP: | ||
1317 | dx = 0; | ||
1318 | dy = -1; | ||
1319 | break; | ||
1320 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT: | ||
1321 | dx = 1; | ||
1322 | dy = -1; | ||
1323 | break; | ||
1324 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT: | ||
1325 | dx = 1; | ||
1326 | dy = 0; | ||
1327 | default: | ||
1328 | break; | ||
1329 | } | ||
1330 | shx1 = dx * shad_dst; | ||
1331 | shx1 -= shad_sz; | ||
1332 | shx2 = dx * shad_dst; | ||
1333 | shx2 += shad_sz; | ||
1334 | if (shx1 < minx) minx = shx1; | ||
1335 | if (shx2 > maxx) maxx = shx2; | ||
1336 | |||
1337 | shy1 = dy * shad_dst; | ||
1338 | shy1 -= shad_sz; | ||
1339 | shy2 = dy * shad_dst; | ||
1340 | shy2 += shad_sz; | ||
1341 | if (shy1 < miny) miny = shy1; | ||
1342 | if (shy2 > maxy) maxy = shy2; | ||
1343 | } | ||
1344 | |||
1345 | if (l) sl = *l; | ||
1346 | if (r) sr = *r; | ||
1347 | if (t) st = *t; | ||
1348 | if (b) sb = *b; | ||
1349 | |||
1350 | if (sr < maxx) sr = maxx; | ||
1351 | if (sl < -minx) sl = -minx; | ||
1352 | if (sb < maxy) sb = maxy; | ||
1353 | if (st < -miny) st = -miny; | ||
1354 | } | ||
1355 | |||
1356 | if (l) *l = sl; | ||
1357 | if (r) *r = sr; | ||
1358 | if (t) *t = st; | ||
1359 | if (b) *b = sb; | ||
1360 | } | ||
1361 | |||
1362 | /* all nice and private */ | ||
1363 | static void | ||
1364 | evas_object_text_init(Evas_Object *obj) | ||
1365 | { | ||
1366 | /* alloc text ob, setup methods and default values */ | ||
1367 | obj->object_data = evas_object_text_new(); | ||
1368 | /* set up default settings for this kind of object */ | ||
1369 | obj->cur.color.r = 255; | ||
1370 | obj->cur.color.g = 255; | ||
1371 | obj->cur.color.b = 255; | ||
1372 | obj->cur.color.a = 255; | ||
1373 | obj->cur.geometry.x = 0; | ||
1374 | obj->cur.geometry.y = 0; | ||
1375 | obj->cur.geometry.w = 0; | ||
1376 | obj->cur.geometry.h = 0; | ||
1377 | obj->cur.layer = 0; | ||
1378 | /* set up object-specific settings */ | ||
1379 | obj->prev = obj->cur; | ||
1380 | /* set up methods (compulsory) */ | ||
1381 | obj->func = &object_func; | ||
1382 | obj->type = o_type; | ||
1383 | } | ||
1384 | |||
1385 | static void * | ||
1386 | evas_object_text_new(void) | ||
1387 | { | ||
1388 | Evas_Object_Text *o; | ||
1389 | |||
1390 | /* alloc obj private data */ | ||
1391 | EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_text", Evas_Object_Text, 128, NULL); | ||
1392 | o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Text); | ||
1393 | if (!o) return NULL; | ||
1394 | EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Text); | ||
1395 | o->magic = MAGIC_OBJ_TEXT; | ||
1396 | o->prev = o->cur; | ||
1397 | #ifdef BIDI_SUPPORT | ||
1398 | o->bidi_par_props = evas_bidi_paragraph_props_new(); | ||
1399 | #endif | ||
1400 | return o; | ||
1401 | } | ||
1402 | |||
1403 | static void | ||
1404 | evas_object_text_free(Evas_Object *obj) | ||
1405 | { | ||
1406 | Evas_Object_Text *o; | ||
1407 | |||
1408 | /* frees private object data. very simple here */ | ||
1409 | o = (Evas_Object_Text *)(obj->object_data); | ||
1410 | MAGIC_CHECK(o, Evas_Object_Text, MAGIC_OBJ_TEXT); | ||
1411 | return; | ||
1412 | MAGIC_CHECK_END(); | ||
1413 | /* free obj */ | ||
1414 | if (o->items) _evas_object_text_items_clear(o); | ||
1415 | if (o->cur.utf8_text) eina_stringshare_del(o->cur.utf8_text); | ||
1416 | if (o->cur.font) eina_stringshare_del(o->cur.font); | ||
1417 | if (o->cur.fdesc) evas_font_desc_unref(o->cur.fdesc); | ||
1418 | if (o->cur.source) eina_stringshare_del(o->cur.source); | ||
1419 | if (o->font) evas_font_free(obj->layer->evas, o->font); | ||
1420 | #ifdef BIDI_SUPPORT | ||
1421 | evas_bidi_paragraph_props_unref(o->bidi_par_props); | ||
1422 | #endif | ||
1423 | o->magic = 0; | ||
1424 | EVAS_MEMPOOL_FREE(_mp_obj, o); | ||
1425 | } | ||
1426 | |||
1427 | static void | ||
1428 | evas_object_text_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y) | ||
1429 | { | ||
1430 | int i, j; | ||
1431 | Evas_Object_Text *o; | ||
1432 | Evas_Object_Text_Item *it; | ||
1433 | const char vals[5][5] = | ||
1434 | { | ||
1435 | {0, 1, 2, 1, 0}, | ||
1436 | {1, 3, 4, 3, 1}, | ||
1437 | {2, 4, 5, 4, 2}, | ||
1438 | {1, 3, 4, 3, 1}, | ||
1439 | {0, 1, 2, 1, 0} | ||
1440 | }; | ||
1441 | int sl = 0, st = 0; | ||
1442 | int shad_dst, shad_sz, dx, dy, haveshad; | ||
1443 | |||
1444 | /* render object to surface with context, and offxet by x,y */ | ||
1445 | o = (Evas_Object_Text *)(obj->object_data); | ||
1446 | evas_text_style_pad_get(o->cur.style, &sl, NULL, &st, NULL); | ||
1447 | ENFN->context_multiplier_unset(output, context); | ||
1448 | ENFN->context_render_op_set(output, context, obj->cur.render_op); | ||
1449 | /* FIXME: This clipping is just until we fix inset handling correctly. */ | ||
1450 | ENFN->context_clip_clip(output, context, | ||
1451 | obj->cur.geometry.x + x, | ||
1452 | obj->cur.geometry.y + y, | ||
1453 | obj->cur.geometry.w, | ||
1454 | obj->cur.geometry.h); | ||
1455 | /* | ||
1456 | ENFN->context_color_set(output, | ||
1457 | context, | ||
1458 | 230, 160, 30, 100); | ||
1459 | ENFN->rectangle_draw(output, | ||
1460 | context, | ||
1461 | surface, | ||
1462 | obj->cur.geometry.x + x, | ||
1463 | obj->cur.geometry.y + y, | ||
1464 | obj->cur.geometry.w, | ||
1465 | obj->cur.geometry.h); | ||
1466 | */ | ||
1467 | #define COLOR_ONLY_SET(object, sub, col) \ | ||
1468 | ENFN->context_color_set(output, context, \ | ||
1469 | object->sub.col.r, \ | ||
1470 | object->sub.col.g, \ | ||
1471 | object->sub.col.b, \ | ||
1472 | object->sub.col.a); | ||
1473 | |||
1474 | #define COLOR_SET(object, sub, col) \ | ||
1475 | if (obj->cur.clipper)\ | ||
1476 | ENFN->context_color_set(output, context, \ | ||
1477 | ((int)object->sub.col.r * ((int)obj->cur.clipper->cur.cache.clip.r + 1)) >> 8, \ | ||
1478 | ((int)object->sub.col.g * ((int)obj->cur.clipper->cur.cache.clip.g + 1)) >> 8, \ | ||
1479 | ((int)object->sub.col.b * ((int)obj->cur.clipper->cur.cache.clip.b + 1)) >> 8, \ | ||
1480 | ((int)object->sub.col.a * ((int)obj->cur.clipper->cur.cache.clip.a + 1)) >> 8); \ | ||
1481 | else\ | ||
1482 | ENFN->context_color_set(output, context, \ | ||
1483 | object->sub.col.r, \ | ||
1484 | object->sub.col.g, \ | ||
1485 | object->sub.col.b, \ | ||
1486 | object->sub.col.a); | ||
1487 | |||
1488 | #define COLOR_SET_AMUL(object, sub, col, amul) \ | ||
1489 | if (obj->cur.clipper) \ | ||
1490 | ENFN->context_color_set(output, context, \ | ||
1491 | (((int)object->sub.col.r) * ((int)obj->cur.clipper->cur.cache.clip.r) * (amul)) / 65025, \ | ||
1492 | (((int)object->sub.col.g) * ((int)obj->cur.clipper->cur.cache.clip.g) * (amul)) / 65025, \ | ||
1493 | (((int)object->sub.col.b) * ((int)obj->cur.clipper->cur.cache.clip.b) * (amul)) / 65025, \ | ||
1494 | (((int)object->sub.col.a) * ((int)obj->cur.clipper->cur.cache.clip.a) * (amul)) / 65025); \ | ||
1495 | else \ | ||
1496 | ENFN->context_color_set(output, context, \ | ||
1497 | (((int)object->sub.col.r) * (amul)) / 255, \ | ||
1498 | (((int)object->sub.col.g) * (amul)) / 255, \ | ||
1499 | (((int)object->sub.col.b) * (amul)) / 255, \ | ||
1500 | (((int)object->sub.col.a) * (amul)) / 255); | ||
1501 | |||
1502 | #define DRAW_TEXT(ox, oy) \ | ||
1503 | if ((o->font) && (it->text_props.len > 0)) \ | ||
1504 | ENFN->font_draw(output, \ | ||
1505 | context, \ | ||
1506 | surface, \ | ||
1507 | o->font, \ | ||
1508 | obj->cur.geometry.x + x + sl + ox + it->x, \ | ||
1509 | obj->cur.geometry.y + y + st + oy + \ | ||
1510 | (int) \ | ||
1511 | (((o->max_ascent * obj->cur.geometry.h) / obj->cur.geometry.h) - 0.5), \ | ||
1512 | obj->cur.geometry.w, \ | ||
1513 | obj->cur.geometry.h, \ | ||
1514 | obj->cur.geometry.w, \ | ||
1515 | obj->cur.geometry.h, \ | ||
1516 | &it->text_props); | ||
1517 | |||
1518 | /* shadows */ | ||
1519 | shad_dst = shad_sz = dx = dy = haveshad = 0; | ||
1520 | switch (o->cur.style & EVAS_TEXT_STYLE_MASK_BASIC) | ||
1521 | { | ||
1522 | case EVAS_TEXT_STYLE_SHADOW: | ||
1523 | case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW: | ||
1524 | shad_dst = 1; | ||
1525 | haveshad = 1; | ||
1526 | break; | ||
1527 | case EVAS_TEXT_STYLE_OUTLINE_SHADOW: | ||
1528 | case EVAS_TEXT_STYLE_FAR_SHADOW: | ||
1529 | shad_dst = 2; | ||
1530 | haveshad = 1; | ||
1531 | break; | ||
1532 | case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW: | ||
1533 | shad_dst = 2; | ||
1534 | shad_sz = 2; | ||
1535 | haveshad = 1; | ||
1536 | break; | ||
1537 | case EVAS_TEXT_STYLE_SOFT_SHADOW: | ||
1538 | shad_dst = 1; | ||
1539 | shad_sz = 2; | ||
1540 | haveshad = 1; | ||
1541 | break; | ||
1542 | default: | ||
1543 | break; | ||
1544 | } | ||
1545 | if (haveshad) | ||
1546 | { | ||
1547 | if (shad_dst > 0) | ||
1548 | { | ||
1549 | switch (o->cur.style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION) | ||
1550 | { | ||
1551 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT: | ||
1552 | dx = 1; | ||
1553 | dy = 1; | ||
1554 | break; | ||
1555 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM: | ||
1556 | dx = 0; | ||
1557 | dy = 1; | ||
1558 | break; | ||
1559 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT: | ||
1560 | dx = -1; | ||
1561 | dy = 1; | ||
1562 | break; | ||
1563 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT: | ||
1564 | dx = -1; | ||
1565 | dy = 0; | ||
1566 | break; | ||
1567 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT: | ||
1568 | dx = -1; | ||
1569 | dy = -1; | ||
1570 | break; | ||
1571 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP: | ||
1572 | dx = 0; | ||
1573 | dy = -1; | ||
1574 | break; | ||
1575 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT: | ||
1576 | dx = 1; | ||
1577 | dy = -1; | ||
1578 | break; | ||
1579 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT: | ||
1580 | dx = 1; | ||
1581 | dy = 0; | ||
1582 | default: | ||
1583 | break; | ||
1584 | } | ||
1585 | dx *= shad_dst; | ||
1586 | dy *= shad_dst; | ||
1587 | } | ||
1588 | } | ||
1589 | EINA_INLIST_FOREACH(EINA_INLIST_GET(o->items), it) | ||
1590 | { | ||
1591 | /* Shadows */ | ||
1592 | if (haveshad) | ||
1593 | { | ||
1594 | switch (shad_sz) | ||
1595 | { | ||
1596 | case 0: | ||
1597 | COLOR_SET(o, cur, shadow); | ||
1598 | DRAW_TEXT(dx, dy); | ||
1599 | break; | ||
1600 | case 2: | ||
1601 | for (j = 0; j < 5; j++) | ||
1602 | { | ||
1603 | for (i = 0; i < 5; i++) | ||
1604 | { | ||
1605 | if (vals[i][j] != 0) | ||
1606 | { | ||
1607 | COLOR_SET_AMUL(o, cur, shadow, vals[i][j] * 50); | ||
1608 | DRAW_TEXT(i - 2 + dx, j - 2 + dy); | ||
1609 | } | ||
1610 | } | ||
1611 | } | ||
1612 | break; | ||
1613 | default: | ||
1614 | break; | ||
1615 | } | ||
1616 | } | ||
1617 | |||
1618 | /* glows */ | ||
1619 | if (o->cur.style == EVAS_TEXT_STYLE_GLOW) | ||
1620 | { | ||
1621 | for (j = 0; j < 5; j++) | ||
1622 | { | ||
1623 | for (i = 0; i < 5; i++) | ||
1624 | { | ||
1625 | if (vals[i][j] != 0) | ||
1626 | { | ||
1627 | COLOR_SET_AMUL(o, cur, glow, vals[i][j] * 50); | ||
1628 | DRAW_TEXT(i - 2, j - 2); | ||
1629 | } | ||
1630 | } | ||
1631 | } | ||
1632 | COLOR_SET(o, cur, glow2); | ||
1633 | DRAW_TEXT(-1, 0); | ||
1634 | DRAW_TEXT(1, 0); | ||
1635 | DRAW_TEXT(0, -1); | ||
1636 | DRAW_TEXT(0, 1); | ||
1637 | } | ||
1638 | |||
1639 | /* outlines */ | ||
1640 | if ((o->cur.style == EVAS_TEXT_STYLE_OUTLINE) || | ||
1641 | (o->cur.style == EVAS_TEXT_STYLE_OUTLINE_SHADOW) || | ||
1642 | (o->cur.style == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW)) | ||
1643 | { | ||
1644 | COLOR_SET(o, cur, outline); | ||
1645 | DRAW_TEXT(-1, 0); | ||
1646 | DRAW_TEXT(1, 0); | ||
1647 | DRAW_TEXT(0, -1); | ||
1648 | DRAW_TEXT(0, 1); | ||
1649 | } | ||
1650 | else if (o->cur.style == EVAS_TEXT_STYLE_SOFT_OUTLINE) | ||
1651 | { | ||
1652 | for (j = 0; j < 5; j++) | ||
1653 | { | ||
1654 | for (i = 0; i < 5; i++) | ||
1655 | { | ||
1656 | if (((i != 2) || (j != 2)) && (vals[i][j] != 0)) | ||
1657 | { | ||
1658 | COLOR_SET_AMUL(o, cur, outline, vals[i][j] * 50); | ||
1659 | DRAW_TEXT(i - 2, j - 2); | ||
1660 | } | ||
1661 | } | ||
1662 | } | ||
1663 | } | ||
1664 | |||
1665 | /* normal text */ | ||
1666 | COLOR_ONLY_SET(obj, cur.cache, clip); | ||
1667 | DRAW_TEXT(0, 0); | ||
1668 | } | ||
1669 | } | ||
1670 | |||
1671 | static void | ||
1672 | evas_object_text_render_pre(Evas_Object *obj) | ||
1673 | { | ||
1674 | Evas_Object_Text *o; | ||
1675 | int is_v, was_v; | ||
1676 | |||
1677 | /* dont pre-render the obj twice! */ | ||
1678 | if (obj->pre_render_done) return; | ||
1679 | obj->pre_render_done = 1; | ||
1680 | /* pre-render phase. this does anything an object needs to do just before | ||
1681 | rendering. This could mean loading the image data, retrieving it from | ||
1682 | elsewhere, decoding video etc. | ||
1683 | Then when this is done the object needs to figure if it changed and | ||
1684 | if so what and where and add the appropriate redraw rectangles */ | ||
1685 | o = (Evas_Object_Text *)(obj->object_data); | ||
1686 | /* if someone is clipping this obj - go calculate the clipper */ | ||
1687 | if (obj->cur.clipper) | ||
1688 | { | ||
1689 | if (obj->cur.cache.clip.dirty) | ||
1690 | evas_object_clip_recalc(obj->cur.clipper); | ||
1691 | obj->cur.clipper->func->render_pre(obj->cur.clipper); | ||
1692 | } | ||
1693 | /* now figure what changed and add draw rects | ||
1694 | if it just became visible or invisible */ | ||
1695 | is_v = evas_object_is_visible(obj); | ||
1696 | was_v = evas_object_was_visible(obj); | ||
1697 | if (is_v != was_v) | ||
1698 | { | ||
1699 | evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, | ||
1700 | obj, is_v, was_v); | ||
1701 | goto done; | ||
1702 | } | ||
1703 | if ((obj->cur.map != obj->prev.map) || | ||
1704 | (obj->cur.usemap != obj->prev.usemap)) | ||
1705 | { | ||
1706 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, | ||
1707 | obj); | ||
1708 | goto done; | ||
1709 | } | ||
1710 | /* its not visible - we accounted for it appearing or not so just abort */ | ||
1711 | if (!is_v) goto done; | ||
1712 | /* clipper changed this is in addition to anything else for obj */ | ||
1713 | evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj); | ||
1714 | /* if we restacked (layer or just within a layer) and dont clip anyone */ | ||
1715 | if (obj->restack) | ||
1716 | { | ||
1717 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, | ||
1718 | obj); | ||
1719 | goto done; | ||
1720 | } | ||
1721 | /* if it changed color */ | ||
1722 | if ((obj->cur.color.r != obj->prev.color.r) || | ||
1723 | (obj->cur.color.g != obj->prev.color.g) || | ||
1724 | (obj->cur.color.b != obj->prev.color.b) || | ||
1725 | (obj->cur.color.a != obj->prev.color.a)) | ||
1726 | { | ||
1727 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, | ||
1728 | obj); | ||
1729 | goto done; | ||
1730 | } | ||
1731 | /* if it changed geometry - and obviously not visibility or color | ||
1732 | calculate differences since we have a constant color fill | ||
1733 | we really only need to update the differences */ | ||
1734 | if ((obj->cur.geometry.x != obj->prev.geometry.x) || | ||
1735 | (obj->cur.geometry.y != obj->prev.geometry.y) || | ||
1736 | (obj->cur.geometry.w != obj->prev.geometry.w) || | ||
1737 | (obj->cur.geometry.h != obj->prev.geometry.h)) | ||
1738 | { | ||
1739 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, | ||
1740 | obj); | ||
1741 | goto done; | ||
1742 | } | ||
1743 | if (obj->cur.render_op != obj->prev.render_op) | ||
1744 | { | ||
1745 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, | ||
1746 | obj); | ||
1747 | goto done; | ||
1748 | } | ||
1749 | if (obj->cur.scale != obj->prev.scale) | ||
1750 | { | ||
1751 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, | ||
1752 | obj); | ||
1753 | goto done; | ||
1754 | } | ||
1755 | if (o->changed) | ||
1756 | { | ||
1757 | if ((o->cur.size != o->prev.size) || | ||
1758 | ((o->cur.font != o->prev.font)) || | ||
1759 | ((o->cur.utf8_text != o->prev.utf8_text)) || | ||
1760 | ((o->cur.style != o->prev.style)) || | ||
1761 | ((o->cur.shadow.r != o->prev.shadow.r)) || | ||
1762 | ((o->cur.shadow.g != o->prev.shadow.g)) || | ||
1763 | ((o->cur.shadow.b != o->prev.shadow.b)) || | ||
1764 | ((o->cur.shadow.a != o->prev.shadow.a)) || | ||
1765 | ((o->cur.outline.r != o->prev.outline.r)) || | ||
1766 | ((o->cur.outline.g != o->prev.outline.g)) || | ||
1767 | ((o->cur.outline.b != o->prev.outline.b)) || | ||
1768 | ((o->cur.outline.a != o->prev.outline.a)) || | ||
1769 | ((o->cur.glow.r != o->prev.glow.r)) || | ||
1770 | ((o->cur.glow.g != o->prev.glow.g)) || | ||
1771 | ((o->cur.glow.b != o->prev.glow.b)) || | ||
1772 | ((o->cur.glow.a != o->prev.glow.a)) || | ||
1773 | ((o->cur.glow2.r != o->prev.glow2.r)) || | ||
1774 | ((o->cur.glow2.g != o->prev.glow2.g)) || | ||
1775 | ((o->cur.glow2.b != o->prev.glow2.b)) || | ||
1776 | ((o->cur.glow2.a != o->prev.glow2.a))) | ||
1777 | { | ||
1778 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, | ||
1779 | obj); | ||
1780 | goto done; | ||
1781 | } | ||
1782 | } | ||
1783 | done: | ||
1784 | evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, | ||
1785 | obj, is_v, was_v); | ||
1786 | } | ||
1787 | |||
1788 | static void | ||
1789 | evas_object_text_render_post(Evas_Object *obj) | ||
1790 | { | ||
1791 | Evas_Object_Text *o; | ||
1792 | |||
1793 | /* this moves the current data to the previous state parts of the object | ||
1794 | in whatever way is safest for the object. also if we don't need object | ||
1795 | data anymore we can free it if the object deems this is a good idea */ | ||
1796 | o = (Evas_Object_Text *)(obj->object_data); | ||
1797 | /* remove those pesky changes */ | ||
1798 | evas_object_clip_changes_clean(obj); | ||
1799 | /* move cur to prev safely for object data */ | ||
1800 | obj->prev = obj->cur; | ||
1801 | o->prev = o->cur; | ||
1802 | o->changed = 0; | ||
1803 | } | ||
1804 | |||
1805 | static unsigned int | ||
1806 | evas_object_text_id_get(Evas_Object *obj) | ||
1807 | { | ||
1808 | Evas_Object_Text *o; | ||
1809 | |||
1810 | o = (Evas_Object_Text *)(obj->object_data); | ||
1811 | if (!o) return 0; | ||
1812 | return MAGIC_OBJ_TEXT; | ||
1813 | } | ||
1814 | |||
1815 | static unsigned int | ||
1816 | evas_object_text_visual_id_get(Evas_Object *obj) | ||
1817 | { | ||
1818 | Evas_Object_Text *o; | ||
1819 | |||
1820 | o = (Evas_Object_Text *)(obj->object_data); | ||
1821 | if (!o) return 0; | ||
1822 | return MAGIC_OBJ_SHAPE; | ||
1823 | } | ||
1824 | |||
1825 | static void * | ||
1826 | evas_object_text_engine_data_get(Evas_Object *obj) | ||
1827 | { | ||
1828 | Evas_Object_Text *o; | ||
1829 | |||
1830 | o = (Evas_Object_Text *)(obj->object_data); | ||
1831 | if (!o) return NULL; | ||
1832 | return o->font; | ||
1833 | } | ||
1834 | |||
1835 | static int | ||
1836 | evas_object_text_is_opaque(Evas_Object *obj __UNUSED__) | ||
1837 | { | ||
1838 | /* this returns 1 if the internal object data implies that the object is | ||
1839 | currently fully opaque over the entire gradient it occupies */ | ||
1840 | return 0; | ||
1841 | } | ||
1842 | |||
1843 | static int | ||
1844 | evas_object_text_was_opaque(Evas_Object *obj __UNUSED__) | ||
1845 | { | ||
1846 | /* this returns 1 if the internal object data implies that the object was | ||
1847 | currently fully opaque over the entire gradient it occupies */ | ||
1848 | return 0; | ||
1849 | } | ||
1850 | |||
1851 | static void | ||
1852 | evas_object_text_scale_update(Evas_Object *obj) | ||
1853 | { | ||
1854 | Evas_Object_Text *o; | ||
1855 | int size; | ||
1856 | const char *font; | ||
1857 | |||
1858 | o = (Evas_Object_Text *)(obj->object_data); | ||
1859 | font = eina_stringshare_add(o->cur.font); | ||
1860 | size = o->cur.size; | ||
1861 | if (o->cur.font) eina_stringshare_del(o->cur.font); | ||
1862 | o->cur.font = NULL; | ||
1863 | o->prev.font = NULL; | ||
1864 | o->cur.size = 0; | ||
1865 | o->prev.size = 0; | ||
1866 | evas_object_text_font_set(obj, font, size); | ||
1867 | } | ||
1868 | |||
1869 | void | ||
1870 | _evas_object_text_rehint(Evas_Object *obj) | ||
1871 | { | ||
1872 | Evas_Object_Text *o; | ||
1873 | int is, was; | ||
1874 | |||
1875 | o = (Evas_Object_Text *)(obj->object_data); | ||
1876 | if (!o->font) return; | ||
1877 | #ifdef EVAS_FRAME_QUEUING | ||
1878 | evas_common_pipe_op_text_flush((RGBA_Font *) o->font); | ||
1879 | #endif | ||
1880 | evas_font_load_hinting_set(obj->layer->evas, o->font, | ||
1881 | obj->layer->evas->hinting); | ||
1882 | was = evas_object_is_in_output_rect(obj, | ||
1883 | obj->layer->evas->pointer.x, | ||
1884 | obj->layer->evas->pointer.y, 1, 1); | ||
1885 | /* DO II */ | ||
1886 | _evas_object_text_recalc(obj); | ||
1887 | o->changed = 1; | ||
1888 | evas_object_change(obj); | ||
1889 | evas_object_clip_dirty(obj); | ||
1890 | evas_object_coords_recalc(obj); | ||
1891 | is = evas_object_is_in_output_rect(obj, | ||
1892 | obj->layer->evas->pointer.x, | ||
1893 | obj->layer->evas->pointer.y, 1, 1); | ||
1894 | if ((is || was) && obj->cur.visible) | ||
1895 | evas_event_feed_mouse_move(obj->layer->evas, | ||
1896 | obj->layer->evas->pointer.x, | ||
1897 | obj->layer->evas->pointer.y, | ||
1898 | obj->layer->evas->last_timestamp, | ||
1899 | NULL); | ||
1900 | evas_object_inform_call_resize(obj); | ||
1901 | } | ||
1902 | |||
1903 | static void | ||
1904 | _evas_object_text_recalc(Evas_Object *obj) | ||
1905 | { | ||
1906 | Evas_Object_Text *o; | ||
1907 | Eina_Unicode *text = NULL; | ||
1908 | o = (Evas_Object_Text *)(obj->object_data); | ||
1909 | |||
1910 | if (o->items) _evas_object_text_items_clear(o); | ||
1911 | if (o->cur.utf8_text) | ||
1912 | text = eina_unicode_utf8_to_unicode(o->cur.utf8_text, | ||
1913 | NULL); | ||
1914 | |||
1915 | if (!text) text = eina_unicode_strdup(EINA_UNICODE_EMPTY_STRING); | ||
1916 | |||
1917 | _evas_object_text_layout(obj, o, text); | ||
1918 | |||
1919 | if (text) free(text); | ||
1920 | |||
1921 | if ((o->font) && (o->items)) | ||
1922 | { | ||
1923 | int w, h; | ||
1924 | int l = 0, r = 0, t = 0, b = 0; | ||
1925 | |||
1926 | w = _evas_object_text_horiz_advance_get(obj, o); | ||
1927 | h = _evas_object_text_vert_advance_get(obj, o); | ||
1928 | evas_text_style_pad_get(o->cur.style, &l, &r, &t, &b); | ||
1929 | obj->cur.geometry.w = w + l + r; | ||
1930 | obj->cur.geometry.h = h + t + b; | ||
1931 | //// obj->cur.cache.geometry.validity = 0; | ||
1932 | } | ||
1933 | else | ||
1934 | { | ||
1935 | int t = 0, b = 0; | ||
1936 | |||
1937 | evas_text_style_pad_get(o->cur.style, NULL, NULL, &t, &b); | ||
1938 | obj->cur.geometry.w = 0; | ||
1939 | obj->cur.geometry.h = o->max_ascent + o->max_descent + t + b; | ||
1940 | //// obj->cur.cache.geometry.validity = 0; | ||
1941 | } | ||
1942 | } | ||
1943 | |||
diff --git a/libraries/evas/src/lib/canvas/evas_object_textblock.c b/libraries/evas/src/lib/canvas/evas_object_textblock.c new file mode 100644 index 0000000..7941a45 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_object_textblock.c | |||
@@ -0,0 +1,9569 @@ | |||
1 | /** | ||
2 | * @internal | ||
3 | * @section Evas_Object_Textblock_Internal Internal Textblock Object Tutorial | ||
4 | * | ||
5 | * This explains the internal design of the Evas Textblock Object, it's assumed | ||
6 | * that the reader of this section has already read @ref Evas_Object_Textblock_Tutorial "Textblock's usage docs.". | ||
7 | * | ||
8 | * @subsection textblock_internal_intro Introduction | ||
9 | * There are two main parts to the textblock object, the first being the node | ||
10 | * system, and the second being the layout system. The former is just an | ||
11 | * internal representation of the markup text, while the latter is the internal | ||
12 | * visual representation of the text (i.e positioning, sizing, fonts and etc). | ||
13 | * | ||
14 | * @subsection textblock_nodes The Nodes system | ||
15 | * The nodes mechanism consists of two main data types: | ||
16 | * ::Evas_Object_Textblock_Node_Text and ::Evas_Object_Textblock_Node_Format | ||
17 | * the former is for Text nodes and the latter is for format nodes. | ||
18 | * There's always at least one text node, even if there are only formats. | ||
19 | * | ||
20 | * @subsection textblock_nodes_text Text nodes | ||
21 | * Each text node is essentially a paragraph, it includes an @ref Eina_UStrbuf | ||
22 | * that stores the actual paragraph text, a utf8 string to store the paragraph | ||
23 | * text in utf8 (which is not used internally at all), A pointer to it's | ||
24 | * main @ref textblock_nodes_format_internal "Format Node" and the paragraph's | ||
25 | * @ref evas_bidi_props "BiDi properties". The pointer to the format node may be | ||
26 | * NULL if there's no format node anywhere before the end of the text node, | ||
27 | * not even in previous text nodes. If not NULL, it points to the first format | ||
28 | * node pointing to text inside of the text node, or if there is none, it points | ||
29 | * to the previous's text nodes format node. Each paragraph has a format node | ||
30 | * representing a paragraph separator pointing to it's last position except | ||
31 | * for the last paragraph, which has no such constraint. This constraint | ||
32 | * happens because text nodes are paragraphs and paragraphs are delimited by | ||
33 | * paragraph separators. | ||
34 | * | ||
35 | * @subsection textblock_nodes_format_internal Format Nodes - Internal | ||
36 | * Each format node stores a group of format information, for example the | ||
37 | * markup: \<font=Vera,Kochi font_size=10 align=left\> will all be inserted | ||
38 | * inside the same format node, altohugh it consists of different formatting | ||
39 | * commands. | ||
40 | * Each node has a pointer to it's text node, this pointer is NEVER NULL, even | ||
41 | * if there's only one format, and no text, a text node is created. Each format | ||
42 | * node includes an offset from the last format node of the same text node. For | ||
43 | * example, the markup "0<b>12</b>" will create two format nodes, the first | ||
44 | * having an offset of 1 and the second an offset of 2. Each format node also | ||
45 | * includes a @ref Eina_Strbuf that includes the textual representation of the | ||
46 | * format, and a boolean stating if the format is a visible format or not, see | ||
47 | * @ref textblock_nodes_format_visible | ||
48 | * | ||
49 | * @subsection textblock_nodes_format_visible Visible Format Nodes | ||
50 | * There are two types of format nodes, visible and invisible. They are the same | ||
51 | * in every way, except for the representation in the text node. While invisible | ||
52 | * format nodes have no representation in the text node, the visible ones do. | ||
53 | * The Uniceode object replacement character (0xFFFC) is inserted to every place | ||
54 | * a visible format node points to. This makes it very easy to treat visible | ||
55 | * formats as items in the text, both for BiDi purposes and cursor handling | ||
56 | * purposes. | ||
57 | * Here are a few example visible an invisible formats: | ||
58 | * Visible: newline char, tab, paragraph separator and an embedded item. | ||
59 | * Invisible: setting the color, font or alignment of the text. | ||
60 | * | ||
61 | * @subsection textblock_layout The layout system | ||
62 | * @todo write @ref textblock_layout | ||
63 | */ | ||
64 | #include <stdlib.h> | ||
65 | |||
66 | #include "evas_common.h" | ||
67 | #include "evas_private.h" | ||
68 | |||
69 | #ifdef HAVE_LINEBREAK | ||
70 | #include "linebreak.h" | ||
71 | #endif | ||
72 | |||
73 | /* save typing */ | ||
74 | #define ENFN obj->layer->evas->engine.func | ||
75 | #define ENDT obj->layer->evas->engine.data.output | ||
76 | |||
77 | /* private magic number for textblock objects */ | ||
78 | static const char o_type[] = "textblock"; | ||
79 | |||
80 | /* The char to be inserted instead of visible formats */ | ||
81 | #define EVAS_TEXTBLOCK_REPLACEMENT_CHAR 0xFFFC | ||
82 | #define _PARAGRAPH_SEPARATOR 0x2029 | ||
83 | #define EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(ch) \ | ||
84 | (((ch) == EVAS_TEXTBLOCK_REPLACEMENT_CHAR) || \ | ||
85 | ((ch) == '\n') || \ | ||
86 | ((ch) == '\t') || \ | ||
87 | ((ch) == _PARAGRAPH_SEPARATOR)) | ||
88 | |||
89 | /* private struct for textblock object internal data */ | ||
90 | /** | ||
91 | * @internal | ||
92 | * @typedef Evas_Object_Textblock | ||
93 | * The actual textblock object. | ||
94 | */ | ||
95 | typedef struct _Evas_Object_Textblock Evas_Object_Textblock; | ||
96 | /** | ||
97 | * @internal | ||
98 | * @typedef Evas_Object_Style_Tag | ||
99 | * The structure used for finding style tags. | ||
100 | */ | ||
101 | typedef struct _Evas_Object_Style_Tag Evas_Object_Style_Tag; | ||
102 | /** | ||
103 | * @internal | ||
104 | * @typedef Evas_Object_Textblock_Node_Text | ||
105 | * A text node. | ||
106 | */ | ||
107 | typedef struct _Evas_Object_Textblock_Node_Text Evas_Object_Textblock_Node_Text; | ||
108 | /* | ||
109 | * Defined in Evas.h | ||
110 | typedef struct _Evas_Object_Textblock_Node_Format Evas_Object_Textblock_Node_Format; | ||
111 | */ | ||
112 | |||
113 | /** | ||
114 | * @internal | ||
115 | * @typedef Evas_Object_Textblock_Paragraph | ||
116 | * A layouting paragraph. | ||
117 | */ | ||
118 | typedef struct _Evas_Object_Textblock_Paragraph Evas_Object_Textblock_Paragraph; | ||
119 | /** | ||
120 | * @internal | ||
121 | * @typedef Evas_Object_Textblock_Line | ||
122 | * A layouting line. | ||
123 | */ | ||
124 | typedef struct _Evas_Object_Textblock_Line Evas_Object_Textblock_Line; | ||
125 | /** | ||
126 | * @internal | ||
127 | * @typedef Evas_Object_Textblock_Item | ||
128 | * A layouting item. | ||
129 | */ | ||
130 | typedef struct _Evas_Object_Textblock_Item Evas_Object_Textblock_Item; | ||
131 | /** | ||
132 | * @internal | ||
133 | * @typedef Evas_Object_Textblock_Item | ||
134 | * A layouting text item. | ||
135 | */ | ||
136 | typedef struct _Evas_Object_Textblock_Text_Item Evas_Object_Textblock_Text_Item; | ||
137 | /** | ||
138 | * @internal | ||
139 | * @typedef Evas_Object_Textblock_Format_Item | ||
140 | * A layouting format item. | ||
141 | */ | ||
142 | typedef struct _Evas_Object_Textblock_Format_Item Evas_Object_Textblock_Format_Item; | ||
143 | /** | ||
144 | * @internal | ||
145 | * @typedef Evas_Object_Textblock_Format | ||
146 | * A textblock format. | ||
147 | */ | ||
148 | typedef struct _Evas_Object_Textblock_Format Evas_Object_Textblock_Format; | ||
149 | |||
150 | /** | ||
151 | * @internal | ||
152 | * @def IS_AT_END(ti, ind) | ||
153 | * Return true if ind is at the end of the text item, false otherwise. | ||
154 | */ | ||
155 | #define IS_AT_END(ti, ind) (ind == ti->text_props.text_len) | ||
156 | |||
157 | /** | ||
158 | * @internal | ||
159 | * @def MOVE_PREV_UNTIL(limit, ind) | ||
160 | * This decrements ind as long as ind > limit. | ||
161 | */ | ||
162 | #define MOVE_PREV_UNTIL(limit, ind) \ | ||
163 | do \ | ||
164 | { \ | ||
165 | if ((limit) < (ind)) \ | ||
166 | (ind)--; \ | ||
167 | } \ | ||
168 | while (0) | ||
169 | |||
170 | /** | ||
171 | * @internal | ||
172 | * @def MOVE_NEXT_UNTIL(limit, ind) | ||
173 | * This increments ind as long as ind < limit | ||
174 | */ | ||
175 | #define MOVE_NEXT_UNTIL(limit, ind) \ | ||
176 | do \ | ||
177 | { \ | ||
178 | if ((ind) < (limit)) \ | ||
179 | (ind)++; \ | ||
180 | } \ | ||
181 | while (0) | ||
182 | |||
183 | /** | ||
184 | * @internal | ||
185 | * @def GET_ITEM_TEXT(ti) | ||
186 | * Returns a const reference to the text of the ti (not null terminated). | ||
187 | */ | ||
188 | #define GET_ITEM_TEXT(ti) \ | ||
189 | (((ti)->parent.text_node) ? \ | ||
190 | (eina_ustrbuf_string_get((ti)->parent.text_node->unicode) + \ | ||
191 | (ti)->parent.text_pos) : EINA_UNICODE_EMPTY_STRING) | ||
192 | /** | ||
193 | * @internal | ||
194 | * @def _FORMAT_IS_CLOSER_OF(base, closer, closer_len) | ||
195 | * Returns true if closer is the closer of base. | ||
196 | */ | ||
197 | #define _FORMAT_IS_CLOSER_OF(base, closer, closer_len) \ | ||
198 | (!strncmp(base + 1, closer, closer_len) && \ | ||
199 | (!base[closer_len + 1] || \ | ||
200 | (base[closer_len + 1] == '=') || \ | ||
201 | _is_white(base[closer_len + 1]))) | ||
202 | |||
203 | /*FIXME: document the structs and struct items. */ | ||
204 | struct _Evas_Object_Style_Tag | ||
205 | { | ||
206 | EINA_INLIST; | ||
207 | char *tag; | ||
208 | char *replace; | ||
209 | size_t tag_len; | ||
210 | size_t replace_len; | ||
211 | }; | ||
212 | |||
213 | struct _Evas_Object_Textblock_Node_Text | ||
214 | { | ||
215 | EINA_INLIST; | ||
216 | Eina_UStrbuf *unicode; | ||
217 | char *utf8; | ||
218 | Evas_Object_Textblock_Node_Format *format_node; | ||
219 | Evas_Object_Textblock_Paragraph *par; | ||
220 | Eina_Bool dirty : 1; | ||
221 | Eina_Bool is_new : 1; | ||
222 | }; | ||
223 | |||
224 | struct _Evas_Object_Textblock_Node_Format | ||
225 | { | ||
226 | EINA_INLIST; | ||
227 | const char *format; | ||
228 | const char *orig_format; | ||
229 | Evas_Object_Textblock_Node_Text *text_node; | ||
230 | size_t offset; | ||
231 | unsigned char anchor : 2; | ||
232 | Eina_Bool visible : 1; | ||
233 | Eina_Bool format_change : 1; | ||
234 | Eina_Bool is_new : 1; | ||
235 | }; | ||
236 | |||
237 | #define ANCHOR_NONE 0 | ||
238 | #define ANCHOR_A 1 | ||
239 | #define ANCHOR_ITEM 2 | ||
240 | |||
241 | /** | ||
242 | * @internal | ||
243 | * @def _NODE_TEXT(x) | ||
244 | * A convinience macro for casting to a text node. | ||
245 | */ | ||
246 | #define _NODE_TEXT(x) ((Evas_Object_Textblock_Node_Text *) (x)) | ||
247 | /** | ||
248 | * @internal | ||
249 | * @def _NODE_FORMAT(x) | ||
250 | * A convinience macro for casting to a format node. | ||
251 | */ | ||
252 | #define _NODE_FORMAT(x) ((Evas_Object_Textblock_Node_Format *) (x)) | ||
253 | /** | ||
254 | * @internal | ||
255 | * @def _ITEM(x) | ||
256 | * A convinience macro for casting to a generic item. | ||
257 | */ | ||
258 | #define _ITEM(x) ((Evas_Object_Textblock_Item *) (x)) | ||
259 | /** | ||
260 | * @internal | ||
261 | * @def _ITEM_TEXT(x) | ||
262 | * A convinience macro for casting to a text item. | ||
263 | */ | ||
264 | #define _ITEM_TEXT(x) ((Evas_Object_Textblock_Text_Item *) (x)) | ||
265 | /** | ||
266 | * @internal | ||
267 | * @def _ITEM_FORMAT(x) | ||
268 | * A convinience macro for casting to a format item. | ||
269 | */ | ||
270 | #define _ITEM_FORMAT(x) ((Evas_Object_Textblock_Format_Item *) (x)) | ||
271 | |||
272 | struct _Evas_Object_Textblock_Paragraph | ||
273 | { | ||
274 | EINA_INLIST; | ||
275 | Evas_Object_Textblock_Line *lines; | ||
276 | Evas_Object_Textblock_Node_Text *text_node; | ||
277 | Eina_List *logical_items; | ||
278 | Evas_BiDi_Paragraph_Props *bidi_props; /* Only valid during layout */ | ||
279 | Evas_BiDi_Direction direction; | ||
280 | Evas_Coord y, w, h; | ||
281 | int line_no; | ||
282 | Eina_Bool is_bidi : 1; | ||
283 | Eina_Bool visible : 1; | ||
284 | Eina_Bool rendered : 1; | ||
285 | }; | ||
286 | |||
287 | struct _Evas_Object_Textblock_Line | ||
288 | { | ||
289 | EINA_INLIST; | ||
290 | Evas_Object_Textblock_Item *items; | ||
291 | Evas_Object_Textblock_Paragraph *par; | ||
292 | Evas_Coord x, y, w, h; | ||
293 | int baseline; | ||
294 | int line_no; | ||
295 | }; | ||
296 | |||
297 | typedef enum _Evas_Textblock_Item_Type | ||
298 | { | ||
299 | EVAS_TEXTBLOCK_ITEM_TEXT, | ||
300 | EVAS_TEXTBLOCK_ITEM_FORMAT, | ||
301 | } Evas_Textblock_Item_Type; | ||
302 | |||
303 | struct _Evas_Object_Textblock_Item | ||
304 | { | ||
305 | EINA_INLIST; | ||
306 | Evas_Textblock_Item_Type type; | ||
307 | Evas_Object_Textblock_Node_Text *text_node; | ||
308 | Evas_Object_Textblock_Format *format; | ||
309 | size_t text_pos; | ||
310 | #ifdef BIDI_SUPPORT | ||
311 | size_t visual_pos; | ||
312 | #endif | ||
313 | Evas_Coord adv, x, w, h; | ||
314 | Eina_Bool merge : 1; /* Indicates whether this | ||
315 | item should merge to the | ||
316 | previous item or not */ | ||
317 | Eina_Bool visually_deleted : 1; | ||
318 | /* Indicates whether this | ||
319 | item is used in the visual | ||
320 | layout or not. */ | ||
321 | }; | ||
322 | |||
323 | struct _Evas_Object_Textblock_Text_Item | ||
324 | { | ||
325 | Evas_Object_Textblock_Item parent; | ||
326 | Evas_Text_Props text_props; | ||
327 | Evas_Coord inset; | ||
328 | Evas_Coord x_adjustment; /* Used to indicate by how | ||
329 | much we adjusted sizes */ | ||
330 | }; | ||
331 | |||
332 | struct _Evas_Object_Textblock_Format_Item | ||
333 | { | ||
334 | Evas_Object_Textblock_Item parent; | ||
335 | Evas_BiDi_Direction bidi_dir; | ||
336 | const char *item; | ||
337 | int y; | ||
338 | unsigned char vsize : 2; | ||
339 | unsigned char size : 2; | ||
340 | Eina_Bool formatme : 1; | ||
341 | }; | ||
342 | |||
343 | struct _Evas_Object_Textblock_Format | ||
344 | { | ||
345 | Evas_Object_Textblock_Node_Format *fnode; | ||
346 | double halign; | ||
347 | double valign; | ||
348 | struct { | ||
349 | Evas_Font_Description *fdesc; | ||
350 | const char *source; | ||
351 | Evas_Font_Set *font; | ||
352 | Evas_Font_Size size; | ||
353 | } font; | ||
354 | struct { | ||
355 | struct { | ||
356 | unsigned char r, g, b, a; | ||
357 | } normal, underline, underline2, underline_dash, outline, shadow, glow, glow2, backing, | ||
358 | strikethrough; | ||
359 | } color; | ||
360 | struct { | ||
361 | int l, r; | ||
362 | } margin; | ||
363 | int ref; | ||
364 | int tabstops; | ||
365 | int linesize; | ||
366 | int linegap; | ||
367 | int underline_dash_width; | ||
368 | int underline_dash_gap; | ||
369 | double linerelsize; | ||
370 | double linerelgap; | ||
371 | double linefill; | ||
372 | double ellipsis; | ||
373 | unsigned char style; | ||
374 | Eina_Bool wrap_word : 1; | ||
375 | Eina_Bool wrap_char : 1; | ||
376 | Eina_Bool wrap_mixed : 1; | ||
377 | Eina_Bool underline : 1; | ||
378 | Eina_Bool underline2 : 1; | ||
379 | Eina_Bool underline_dash : 1; | ||
380 | Eina_Bool strikethrough : 1; | ||
381 | Eina_Bool backing : 1; | ||
382 | Eina_Bool password : 1; | ||
383 | Eina_Bool halign_auto : 1; | ||
384 | }; | ||
385 | |||
386 | struct _Evas_Textblock_Style | ||
387 | { | ||
388 | const char *style_text; | ||
389 | char *default_tag; | ||
390 | Evas_Object_Style_Tag *tags; | ||
391 | Eina_List *objects; | ||
392 | Eina_Bool delete_me : 1; | ||
393 | }; | ||
394 | |||
395 | struct _Evas_Textblock_Cursor | ||
396 | { | ||
397 | Evas_Object *obj; | ||
398 | size_t pos; | ||
399 | Evas_Object_Textblock_Node_Text *node; | ||
400 | }; | ||
401 | |||
402 | /* Size of the index array */ | ||
403 | #define TEXTBLOCK_PAR_INDEX_SIZE 10 | ||
404 | struct _Evas_Object_Textblock | ||
405 | { | ||
406 | DATA32 magic; | ||
407 | Evas_Textblock_Style *style; | ||
408 | Evas_Textblock_Cursor *cursor; | ||
409 | Eina_List *cursors; | ||
410 | Evas_Object_Textblock_Node_Text *text_nodes; | ||
411 | Evas_Object_Textblock_Node_Format *format_nodes; | ||
412 | |||
413 | int num_paragraphs; | ||
414 | Evas_Object_Textblock_Paragraph *paragraphs; | ||
415 | Evas_Object_Textblock_Paragraph *par_index[TEXTBLOCK_PAR_INDEX_SIZE]; | ||
416 | |||
417 | Evas_Object_Textblock_Text_Item *ellip_ti; | ||
418 | Eina_List *anchors_a; | ||
419 | Eina_List *anchors_item; | ||
420 | int last_w, last_h; | ||
421 | struct { | ||
422 | int l, r, t, b; | ||
423 | } style_pad; | ||
424 | double valign; | ||
425 | char *markup_text; | ||
426 | void *engine_data; | ||
427 | const char *repch; | ||
428 | const char *bidi_delimiters; | ||
429 | struct { | ||
430 | int w, h; | ||
431 | Eina_Bool valid : 1; | ||
432 | } formatted, native; | ||
433 | Eina_Bool redraw : 1; | ||
434 | Eina_Bool changed : 1; | ||
435 | Eina_Bool content_changed : 1; | ||
436 | Eina_Bool format_changed : 1; | ||
437 | Eina_Bool have_ellipsis : 1; | ||
438 | Eina_Bool legacy_newline : 1; | ||
439 | }; | ||
440 | |||
441 | /* private methods for textblock objects */ | ||
442 | static void evas_object_textblock_init(Evas_Object *obj); | ||
443 | static void *evas_object_textblock_new(void); | ||
444 | static void evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y); | ||
445 | static void evas_object_textblock_free(Evas_Object *obj); | ||
446 | static void evas_object_textblock_render_pre(Evas_Object *obj); | ||
447 | static void evas_object_textblock_render_post(Evas_Object *obj); | ||
448 | |||
449 | static unsigned int evas_object_textblock_id_get(Evas_Object *obj); | ||
450 | static unsigned int evas_object_textblock_visual_id_get(Evas_Object *obj); | ||
451 | static void *evas_object_textblock_engine_data_get(Evas_Object *obj); | ||
452 | |||
453 | static int evas_object_textblock_is_opaque(Evas_Object *obj); | ||
454 | static int evas_object_textblock_was_opaque(Evas_Object *obj); | ||
455 | |||
456 | static void evas_object_textblock_coords_recalc(Evas_Object *obj); | ||
457 | |||
458 | static void evas_object_textblock_scale_update(Evas_Object *obj); | ||
459 | |||
460 | static const Evas_Object_Func object_func = | ||
461 | { | ||
462 | /* methods (compulsory) */ | ||
463 | evas_object_textblock_free, | ||
464 | evas_object_textblock_render, | ||
465 | evas_object_textblock_render_pre, | ||
466 | evas_object_textblock_render_post, | ||
467 | evas_object_textblock_id_get, | ||
468 | evas_object_textblock_visual_id_get, | ||
469 | evas_object_textblock_engine_data_get, | ||
470 | /* these are optional. NULL = nothing */ | ||
471 | NULL, | ||
472 | NULL, | ||
473 | NULL, | ||
474 | NULL, | ||
475 | evas_object_textblock_is_opaque, | ||
476 | evas_object_textblock_was_opaque, | ||
477 | NULL, | ||
478 | NULL, | ||
479 | evas_object_textblock_coords_recalc, | ||
480 | evas_object_textblock_scale_update, | ||
481 | NULL, | ||
482 | NULL, | ||
483 | NULL | ||
484 | }; | ||
485 | |||
486 | /* the actual api call to add a textblock */ | ||
487 | |||
488 | #define TB_HEAD() \ | ||
489 | Evas_Object_Textblock *o; \ | ||
490 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); \ | ||
491 | return; \ | ||
492 | MAGIC_CHECK_END(); \ | ||
493 | o = (Evas_Object_Textblock *)(obj->object_data); \ | ||
494 | MAGIC_CHECK(o, Evas_Object_Textblock, MAGIC_OBJ_TEXTBLOCK); \ | ||
495 | return; \ | ||
496 | MAGIC_CHECK_END(); | ||
497 | |||
498 | #define TB_HEAD_RETURN(x) \ | ||
499 | Evas_Object_Textblock *o; \ | ||
500 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); \ | ||
501 | return (x); \ | ||
502 | MAGIC_CHECK_END(); \ | ||
503 | o = (Evas_Object_Textblock *)(obj->object_data); \ | ||
504 | MAGIC_CHECK(o, Evas_Object_Textblock, MAGIC_OBJ_TEXTBLOCK); \ | ||
505 | return (x); \ | ||
506 | MAGIC_CHECK_END(); | ||
507 | |||
508 | |||
509 | |||
510 | static Eina_Bool _evas_textblock_cursor_is_at_the_end(const Evas_Textblock_Cursor *cur); | ||
511 | static void _evas_textblock_node_text_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n); | ||
512 | static void _evas_textblock_node_text_remove_formats_between(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n, int start, int end); | ||
513 | static Evas_Object_Textblock_Node_Format *_evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur); | ||
514 | static size_t _evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt); | ||
515 | static void _evas_textblock_node_format_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n, int visual_adjustment); | ||
516 | static void _evas_textblock_node_format_free(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n); | ||
517 | static void _evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n); | ||
518 | static void _evas_textblock_changed(Evas_Object_Textblock *o, Evas_Object *obj); | ||
519 | static void _evas_textblock_invalidate_all(Evas_Object_Textblock *o); | ||
520 | static void _evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Text *n, size_t start, int offset); | ||
521 | static void _evas_textblock_cursors_set_node(Evas_Object_Textblock *o, const Evas_Object_Textblock_Node_Text *n, Evas_Object_Textblock_Node_Text *new_node); | ||
522 | |||
523 | /* styles */ | ||
524 | /** | ||
525 | * @internal | ||
526 | * Clears the textblock style passed except for the style_text which is replaced. | ||
527 | * @param ts The ts to be cleared. Must not be NULL. | ||
528 | * @param style_text the style's text. | ||
529 | */ | ||
530 | static void | ||
531 | _style_replace(Evas_Textblock_Style *ts, const char *style_text) | ||
532 | { | ||
533 | eina_stringshare_replace(&ts->style_text, style_text); | ||
534 | if (ts->default_tag) free(ts->default_tag); | ||
535 | while (ts->tags) | ||
536 | { | ||
537 | Evas_Object_Style_Tag *tag; | ||
538 | |||
539 | tag = (Evas_Object_Style_Tag *)ts->tags; | ||
540 | ts->tags = (Evas_Object_Style_Tag *)eina_inlist_remove(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag)); | ||
541 | free(tag->tag); | ||
542 | free(tag->replace); | ||
543 | free(tag); | ||
544 | } | ||
545 | ts->default_tag = NULL; | ||
546 | ts->tags = NULL; | ||
547 | } | ||
548 | |||
549 | /** | ||
550 | * @internal | ||
551 | * Clears the textblock style passed. | ||
552 | * @param ts The ts to be cleared. Must not be NULL. | ||
553 | */ | ||
554 | static void | ||
555 | _style_clear(Evas_Textblock_Style *ts) | ||
556 | { | ||
557 | _style_replace(ts, NULL); | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * @internal | ||
562 | * Searches inside the tags stored in the style for the tag matching s. | ||
563 | * @param ts The ts to be cleared. Must not be NULL. | ||
564 | * @param s The tag to be matched. | ||
565 | * @param tag_len the length of the tag string. | ||
566 | * @param[out] replace_len The length of the replcaement found. - Must not be NULL. | ||
567 | * @return The replacement string found. | ||
568 | */ | ||
569 | static inline const char * | ||
570 | _style_match_tag(Evas_Textblock_Style *ts, const char *s, size_t tag_len, size_t *replace_len) | ||
571 | { | ||
572 | Evas_Object_Style_Tag *tag; | ||
573 | |||
574 | EINA_INLIST_FOREACH(ts->tags, tag) | ||
575 | { | ||
576 | if (tag->tag_len != tag_len) continue; | ||
577 | if (!strncmp(tag->tag, s, tag_len)) | ||
578 | { | ||
579 | *replace_len = tag->replace_len; | ||
580 | return tag->replace; | ||
581 | } | ||
582 | } | ||
583 | *replace_len = 0; | ||
584 | return NULL; | ||
585 | } | ||
586 | |||
587 | /** | ||
588 | * @internal | ||
589 | * Clears all the nodes (text and format) of the textblock object. | ||
590 | * @param obj The evas object, must not be NULL. | ||
591 | */ | ||
592 | static void | ||
593 | _nodes_clear(const Evas_Object *obj) | ||
594 | { | ||
595 | Evas_Object_Textblock *o; | ||
596 | |||
597 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
598 | while (o->text_nodes) | ||
599 | { | ||
600 | Evas_Object_Textblock_Node_Text *n; | ||
601 | |||
602 | n = o->text_nodes; | ||
603 | o->text_nodes = _NODE_TEXT(eina_inlist_remove( | ||
604 | EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n))); | ||
605 | _evas_textblock_node_text_free(n); | ||
606 | } | ||
607 | while (o->format_nodes) | ||
608 | { | ||
609 | Evas_Object_Textblock_Node_Format *n; | ||
610 | |||
611 | n = o->format_nodes; | ||
612 | o->format_nodes = _NODE_FORMAT(eina_inlist_remove(EINA_INLIST_GET(o->format_nodes), EINA_INLIST_GET(n))); | ||
613 | _evas_textblock_node_format_free(o, n); | ||
614 | } | ||
615 | } | ||
616 | |||
617 | /** | ||
618 | * @internal | ||
619 | * Unrefs and frees (if needed) a textblock format. | ||
620 | * @param obj The Evas_Object, Must not be NULL. | ||
621 | * @param fmt the format to be cleaned, must not be NULL. | ||
622 | */ | ||
623 | static void | ||
624 | _format_unref_free(const Evas_Object *obj, Evas_Object_Textblock_Format *fmt) | ||
625 | { | ||
626 | fmt->ref--; | ||
627 | if (fmt->ref > 0) return; | ||
628 | if (fmt->font.fdesc) evas_font_desc_unref(fmt->font.fdesc); | ||
629 | if (fmt->font.source) eina_stringshare_del(fmt->font.source); | ||
630 | evas_font_free(obj->layer->evas, fmt->font.font); | ||
631 | free(fmt); | ||
632 | } | ||
633 | |||
634 | /** | ||
635 | * @internal | ||
636 | * Free a layout item | ||
637 | * @param obj The evas object, must not be NULL. | ||
638 | * @param ln the layout line on which the item is in, must not be NULL. | ||
639 | * @param it the layout item to be freed | ||
640 | */ | ||
641 | static void | ||
642 | _item_free(const Evas_Object *obj, Evas_Object_Textblock_Line *ln, Evas_Object_Textblock_Item *it) | ||
643 | { | ||
644 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
645 | { | ||
646 | Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it); | ||
647 | |||
648 | evas_common_text_props_content_unref(&ti->text_props); | ||
649 | } | ||
650 | else | ||
651 | { | ||
652 | Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it); | ||
653 | |||
654 | if (fi->item) eina_stringshare_del(fi->item); | ||
655 | } | ||
656 | _format_unref_free(obj, it->format); | ||
657 | if (ln) | ||
658 | { | ||
659 | ln->items = (Evas_Object_Textblock_Item *) eina_inlist_remove( | ||
660 | EINA_INLIST_GET(ln->items), EINA_INLIST_GET(ln->items)); | ||
661 | } | ||
662 | free(it); | ||
663 | } | ||
664 | |||
665 | /** | ||
666 | * @internal | ||
667 | * Free a layout line. | ||
668 | * @param obj The evas object, must not be NULL. | ||
669 | * @param ln the layout line to be freed, must not be NULL. | ||
670 | */ | ||
671 | static void | ||
672 | _line_free(Evas_Object_Textblock_Line *ln) | ||
673 | { | ||
674 | /* Items are freed from the logical list, except for the ellip item */ | ||
675 | if (ln) free(ln); | ||
676 | } | ||
677 | |||
678 | /* table of html escapes (that i can find) this should be ordered with the | ||
679 | * most common first as it's a linear search to match - no hash for this. | ||
680 | * | ||
681 | * these are stored as one large string and one additional array that | ||
682 | * contains the offsets to the tokens for space efficiency. | ||
683 | */ | ||
684 | /** | ||
685 | * @internal | ||
686 | * @var escape_strings[] | ||
687 | * This string consists of NULL terminated pairs of strings, the first of | ||
688 | * every pair is an escape and the second is the value of the escape. | ||
689 | */ | ||
690 | static const char escape_strings[] = | ||
691 | /* most common escaped stuff */ | ||
692 | ""\0" "\x22\0" | ||
693 | "&\0" "\x26\0" | ||
694 | "<\0" "\x3c\0" | ||
695 | ">\0" "\x3e\0" | ||
696 | /* all the rest */ | ||
697 | " \0" "\xc2\xa0\0" | ||
698 | "¡\0" "\xc2\xa1\0" | ||
699 | "¢\0" "\xc2\xa2\0" | ||
700 | "£\0" "\xc2\xa3\0" | ||
701 | "¤\0" "\xc2\xa4\0" | ||
702 | "¥\0" "\xc2\xa5\0" | ||
703 | "¦\0" "\xc2\xa6\0" | ||
704 | "§\0" "\xc2\xa7\0" | ||
705 | "¨\0" "\xc2\xa8\0" | ||
706 | "©\0" "\xc2\xa9\0" | ||
707 | "ª\0" "\xc2\xaa\0" | ||
708 | "«\0" "\xc2\xab\0" | ||
709 | "¬\0" "\xc2\xac\0" | ||
710 | "®\0" "\xc2\xae\0" | ||
711 | "¯\0" "\xc2\xaf\0" | ||
712 | "°\0" "\xc2\xb0\0" | ||
713 | "±\0" "\xc2\xb1\0" | ||
714 | "²\0" "\xc2\xb2\0" | ||
715 | "³\0" "\xc2\xb3\0" | ||
716 | "´\0" "\xc2\xb4\0" | ||
717 | "µ\0" "\xc2\xb5\0" | ||
718 | "¶\0" "\xc2\xb6\0" | ||
719 | "·\0" "\xc2\xb7\0" | ||
720 | "¸\0" "\xc2\xb8\0" | ||
721 | "¹\0" "\xc2\xb9\0" | ||
722 | "º\0" "\xc2\xba\0" | ||
723 | "»\0" "\xc2\xbb\0" | ||
724 | "¼\0" "\xc2\xbc\0" | ||
725 | "½\0" "\xc2\xbd\0" | ||
726 | "¾\0" "\xc2\xbe\0" | ||
727 | "¿\0" "\xc2\xbf\0" | ||
728 | "À\0" "\xc3\x80\0" | ||
729 | "Á\0" "\xc3\x81\0" | ||
730 | "Â\0" "\xc3\x82\0" | ||
731 | "Ã\0" "\xc3\x83\0" | ||
732 | "Ä\0" "\xc3\x84\0" | ||
733 | "Å\0" "\xc3\x85\0" | ||
734 | "&Aelig;\0" "\xc3\x86\0" | ||
735 | "Ç\0" "\xc3\x87\0" | ||
736 | "È\0" "\xc3\x88\0" | ||
737 | "É\0" "\xc3\x89\0" | ||
738 | "Ê\0" "\xc3\x8a\0" | ||
739 | "Ë\0" "\xc3\x8b\0" | ||
740 | "Ì\0" "\xc3\x8c\0" | ||
741 | "Í\0" "\xc3\x8d\0" | ||
742 | "Î\0" "\xc3\x8e\0" | ||
743 | "Ï\0" "\xc3\x8f\0" | ||
744 | "&Eth;\0" "\xc3\x90\0" | ||
745 | "Ñ\0" "\xc3\x91\0" | ||
746 | "Ò\0" "\xc3\x92\0" | ||
747 | "Ó\0" "\xc3\x93\0" | ||
748 | "Ô\0" "\xc3\x94\0" | ||
749 | "Õ\0" "\xc3\x95\0" | ||
750 | "Ö\0" "\xc3\x96\0" | ||
751 | "×\0" "\xc3\x97\0" | ||
752 | "Ø\0" "\xc3\x98\0" | ||
753 | "Ù\0" "\xc3\x99\0" | ||
754 | "Ú\0" "\xc3\x9a\0" | ||
755 | "Û\0" "\xc3\x9b\0" | ||
756 | "Ý\0" "\xc3\x9d\0" | ||
757 | "&Thorn;\0" "\xc3\x9e\0" | ||
758 | "ß\0" "\xc3\x9f\0" | ||
759 | "à\0" "\xc3\xa0\0" | ||
760 | "á\0" "\xc3\xa1\0" | ||
761 | "â\0" "\xc3\xa2\0" | ||
762 | "ã\0" "\xc3\xa3\0" | ||
763 | "ä\0" "\xc3\xa4\0" | ||
764 | "å\0" "\xc3\xa5\0" | ||
765 | "æ\0" "\xc3\xa6\0" | ||
766 | "ç\0" "\xc3\xa7\0" | ||
767 | "è\0" "\xc3\xa8\0" | ||
768 | "é\0" "\xc3\xa9\0" | ||
769 | "ê\0" "\xc3\xaa\0" | ||
770 | "ë\0" "\xc3\xab\0" | ||
771 | "ì\0" "\xc3\xac\0" | ||
772 | "í\0" "\xc3\xad\0" | ||
773 | "î\0" "\xc3\xae\0" | ||
774 | "ï\0" "\xc3\xaf\0" | ||
775 | "ð\0" "\xc3\xb0\0" | ||
776 | "ñ\0" "\xc3\xb1\0" | ||
777 | "ò\0" "\xc3\xb2\0" | ||
778 | "ó\0" "\xc3\xb3\0" | ||
779 | "ô\0" "\xc3\xb4\0" | ||
780 | "õ\0" "\xc3\xb5\0" | ||
781 | "ö\0" "\xc3\xb6\0" | ||
782 | "÷\0" "\xc3\xb7\0" | ||
783 | "ø\0" "\xc3\xb8\0" | ||
784 | "ù\0" "\xc3\xb9\0" | ||
785 | "ú\0" "\xc3\xba\0" | ||
786 | "û\0" "\xc3\xbb\0" | ||
787 | "ü\0" "\xc3\xbc\0" | ||
788 | "ý\0" "\xc3\xbd\0" | ||
789 | "þ\0" "\xc3\xbe\0" | ||
790 | "ÿ\0" "\xc3\xbf\0" | ||
791 | "α\0" "\xce\x91\0" | ||
792 | "β\0" "\xce\x92\0" | ||
793 | "γ\0" "\xce\x93\0" | ||
794 | "δ\0" "\xce\x94\0" | ||
795 | "ε\0" "\xce\x95\0" | ||
796 | "ζ\0" "\xce\x96\0" | ||
797 | "η\0" "\xce\x97\0" | ||
798 | "θ\0" "\xce\x98\0" | ||
799 | "ι\0" "\xce\x99\0" | ||
800 | "κ\0" "\xce\x9a\0" | ||
801 | "λ\0" "\xce\x9b\0" | ||
802 | "μ\0" "\xce\x9c\0" | ||
803 | "ν\0" "\xce\x9d\0" | ||
804 | "ξ\0" "\xce\x9e\0" | ||
805 | "ο\0" "\xce\x9f\0" | ||
806 | "π\0" "\xce\xa0\0" | ||
807 | "ρ\0" "\xce\xa1\0" | ||
808 | "σ\0" "\xce\xa3\0" | ||
809 | "τ\0" "\xce\xa4\0" | ||
810 | "υ\0" "\xce\xa5\0" | ||
811 | "φ\0" "\xce\xa6\0" | ||
812 | "χ\0" "\xce\xa7\0" | ||
813 | "ψ\0" "\xce\xa8\0" | ||
814 | "ω\0" "\xce\xa9\0" | ||
815 | "…\0" "\xe2\x80\xa6\0" | ||
816 | "€\0" "\xe2\x82\xac\0" | ||
817 | "←\0" "\xe2\x86\x90\0" | ||
818 | "↑\0" "\xe2\x86\x91\0" | ||
819 | "→\0" "\xe2\x86\x92\0" | ||
820 | "↓\0" "\xe2\x86\x93\0" | ||
821 | "↔\0" "\xe2\x86\x94\0" | ||
822 | "←\0" "\xe2\x87\x90\0" | ||
823 | "→\0" "\xe2\x87\x92\0" | ||
824 | "∀\0" "\xe2\x88\x80\0" | ||
825 | "∃\0" "\xe2\x88\x83\0" | ||
826 | "∇\0" "\xe2\x88\x87\0" | ||
827 | "∏\0" "\xe2\x88\x8f\0" | ||
828 | "∑\0" "\xe2\x88\x91\0" | ||
829 | "∧\0" "\xe2\x88\xa7\0" | ||
830 | "∨\0" "\xe2\x88\xa8\0" | ||
831 | "∫\0" "\xe2\x88\xab\0" | ||
832 | "≠\0" "\xe2\x89\xa0\0" | ||
833 | "≡\0" "\xe2\x89\xa1\0" | ||
834 | "⊕\0" "\xe2\x8a\x95\0" | ||
835 | "⊥\0" "\xe2\x8a\xa5\0" | ||
836 | "†\0" "\xe2\x80\xa0\0" | ||
837 | "‡\0" "\xe2\x80\xa1\0" | ||
838 | "•\0" "\xe2\x80\xa2\0" | ||
839 | ; | ||
840 | |||
841 | EVAS_MEMPOOL(_mp_obj); | ||
842 | |||
843 | /** | ||
844 | * @internal | ||
845 | * Checks if a char is a whitespace. | ||
846 | * @param c the unicode codepoint. | ||
847 | * @return EINA_TRUE if the unicode codepoint is a whitespace, EINA_FALSE otherwise. | ||
848 | */ | ||
849 | static Eina_Bool | ||
850 | _is_white(Eina_Unicode c) | ||
851 | { | ||
852 | /* | ||
853 | * unicode list of whitespace chars | ||
854 | * | ||
855 | * 0009..000D <control-0009>..<control-000D> | ||
856 | * 0020 SPACE | ||
857 | * 0085 <control-0085> | ||
858 | * 00A0 NO-BREAK SPACE | ||
859 | * 1680 OGHAM SPACE MARK | ||
860 | * 180E MONGOLIAN VOWEL SEPARATOR | ||
861 | * 2000..200A EN QUAD..HAIR SPACE | ||
862 | * 2028 LINE SEPARATOR | ||
863 | * 2029 PARAGRAPH SEPARATOR | ||
864 | * 202F NARROW NO-BREAK SPACE | ||
865 | * 205F MEDIUM MATHEMATICAL SPACE | ||
866 | * 3000 IDEOGRAPHIC SPACE | ||
867 | */ | ||
868 | if ( | ||
869 | (c == 0x20) || | ||
870 | ((c >= 0x9) && (c <= 0xd)) || | ||
871 | (c == 0x85) || | ||
872 | (c == 0xa0) || | ||
873 | (c == 0x1680) || | ||
874 | (c == 0x180e) || | ||
875 | ((c >= 0x2000) && (c <= 0x200a)) || | ||
876 | (c == 0x2028) || | ||
877 | (c == 0x2029) || | ||
878 | (c == 0x202f) || | ||
879 | (c == 0x205f) || | ||
880 | (c == 0x3000) | ||
881 | ) | ||
882 | return EINA_TRUE; | ||
883 | return EINA_FALSE; | ||
884 | } | ||
885 | |||
886 | /** | ||
887 | * @internal | ||
888 | * Prepends the text between s and p to the main cursor of the object. | ||
889 | * | ||
890 | * @param cur the cursor to prepend to. | ||
891 | * @param[in] s start of the string | ||
892 | * @param[in] p end of the string | ||
893 | */ | ||
894 | static void | ||
895 | _prepend_text_run(Evas_Textblock_Cursor *cur, const char *s, const char *p) | ||
896 | { | ||
897 | if ((s) && (p > s)) | ||
898 | { | ||
899 | char *ts; | ||
900 | |||
901 | ts = alloca(p - s + 1); | ||
902 | strncpy(ts, s, p - s); | ||
903 | ts[p - s] = 0; | ||
904 | evas_textblock_cursor_text_prepend(cur, ts); | ||
905 | } | ||
906 | } | ||
907 | |||
908 | |||
909 | /** | ||
910 | * @internal | ||
911 | * Returns the numeric value of HEX chars for example for ch = 'A' | ||
912 | * the function will return 10. | ||
913 | * | ||
914 | * @param ch The HEX char. | ||
915 | * @return numeric value of HEX. | ||
916 | */ | ||
917 | static int | ||
918 | _hex_string_get(char ch) | ||
919 | { | ||
920 | if ((ch >= '0') && (ch <= '9')) return (ch - '0'); | ||
921 | else if ((ch >= 'A') && (ch <= 'F')) return (ch - 'A' + 10); | ||
922 | else if ((ch >= 'a') && (ch <= 'f')) return (ch - 'a' + 10); | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | /** | ||
927 | * @internal | ||
928 | * Parses a string of one of the formas: | ||
929 | * 1. "#RRGGBB" | ||
930 | * 2. "#RRGGBBAA" | ||
931 | * 3. "#RGB" | ||
932 | * 4. "#RGBA" | ||
933 | * To the rgba values. | ||
934 | * | ||
935 | * @param[in] str The string to parse - NOT NULL. | ||
936 | * @param[out] r The Red value - NOT NULL. | ||
937 | * @param[out] g The Green value - NOT NULL. | ||
938 | * @param[out] b The Blue value - NOT NULL. | ||
939 | * @param[out] a The Alpha value - NOT NULL. | ||
940 | */ | ||
941 | static void | ||
942 | _format_color_parse(const char *str, unsigned char *r, unsigned char *g, unsigned char *b, unsigned char *a) | ||
943 | { | ||
944 | int slen; | ||
945 | |||
946 | slen = strlen(str); | ||
947 | *r = *g = *b = *a = 0; | ||
948 | |||
949 | if (slen == 7) /* #RRGGBB */ | ||
950 | { | ||
951 | *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2])); | ||
952 | *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4])); | ||
953 | *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6])); | ||
954 | *a = 0xff; | ||
955 | } | ||
956 | else if (slen == 9) /* #RRGGBBAA */ | ||
957 | { | ||
958 | *r = (_hex_string_get(str[1]) << 4) | (_hex_string_get(str[2])); | ||
959 | *g = (_hex_string_get(str[3]) << 4) | (_hex_string_get(str[4])); | ||
960 | *b = (_hex_string_get(str[5]) << 4) | (_hex_string_get(str[6])); | ||
961 | *a = (_hex_string_get(str[7]) << 4) | (_hex_string_get(str[8])); | ||
962 | } | ||
963 | else if (slen == 4) /* #RGB */ | ||
964 | { | ||
965 | *r = _hex_string_get(str[1]); | ||
966 | *r = (*r << 4) | *r; | ||
967 | *g = _hex_string_get(str[2]); | ||
968 | *g = (*g << 4) | *g; | ||
969 | *b = _hex_string_get(str[3]); | ||
970 | *b = (*b << 4) | *b; | ||
971 | *a = 0xff; | ||
972 | } | ||
973 | else if (slen == 5) /* #RGBA */ | ||
974 | { | ||
975 | *r = _hex_string_get(str[1]); | ||
976 | *r = (*r << 4) | *r; | ||
977 | *g = _hex_string_get(str[2]); | ||
978 | *g = (*g << 4) | *g; | ||
979 | *b = _hex_string_get(str[3]); | ||
980 | *b = (*b << 4) | *b; | ||
981 | *a = _hex_string_get(str[4]); | ||
982 | *a = (*a << 4) | *a; | ||
983 | } | ||
984 | *r = (*r * *a) / 255; | ||
985 | *g = (*g * *a) / 255; | ||
986 | *b = (*b * *a) / 255; | ||
987 | } | ||
988 | |||
989 | /* The refcount for the formats. */ | ||
990 | static int format_refcount = 0; | ||
991 | /* Holders for the stringshares */ | ||
992 | static const char *fontstr = NULL; | ||
993 | static const char *font_fallbacksstr = NULL; | ||
994 | static const char *font_sizestr = NULL; | ||
995 | static const char *font_sourcestr = NULL; | ||
996 | static const char *font_weightstr = NULL; | ||
997 | static const char *font_stylestr = NULL; | ||
998 | static const char *font_widthstr = NULL; | ||
999 | static const char *langstr = NULL; | ||
1000 | static const char *colorstr = NULL; | ||
1001 | static const char *underline_colorstr = NULL; | ||
1002 | static const char *underline2_colorstr = NULL; | ||
1003 | static const char *underline_dash_colorstr = NULL; | ||
1004 | static const char *outline_colorstr = NULL; | ||
1005 | static const char *shadow_colorstr = NULL; | ||
1006 | static const char *glow_colorstr = NULL; | ||
1007 | static const char *glow2_colorstr = NULL; | ||
1008 | static const char *backing_colorstr = NULL; | ||
1009 | static const char *strikethrough_colorstr = NULL; | ||
1010 | static const char *alignstr = NULL; | ||
1011 | static const char *valignstr = NULL; | ||
1012 | static const char *wrapstr = NULL; | ||
1013 | static const char *left_marginstr = NULL; | ||
1014 | static const char *right_marginstr = NULL; | ||
1015 | static const char *underlinestr = NULL; | ||
1016 | static const char *strikethroughstr = NULL; | ||
1017 | static const char *backingstr = NULL; | ||
1018 | static const char *stylestr = NULL; | ||
1019 | static const char *tabstopsstr = NULL; | ||
1020 | static const char *linesizestr = NULL; | ||
1021 | static const char *linerelsizestr = NULL; | ||
1022 | static const char *linegapstr = NULL; | ||
1023 | static const char *linerelgapstr = NULL; | ||
1024 | static const char *itemstr = NULL; | ||
1025 | static const char *linefillstr = NULL; | ||
1026 | static const char *ellipsisstr = NULL; | ||
1027 | static const char *passwordstr = NULL; | ||
1028 | static const char *underline_dash_widthstr = NULL; | ||
1029 | static const char *underline_dash_gapstr = NULL; | ||
1030 | |||
1031 | /** | ||
1032 | * @internal | ||
1033 | * Init the format strings. | ||
1034 | */ | ||
1035 | static void | ||
1036 | _format_command_init(void) | ||
1037 | { | ||
1038 | if (format_refcount == 0) | ||
1039 | { | ||
1040 | fontstr = eina_stringshare_add("font"); | ||
1041 | font_fallbacksstr = eina_stringshare_add("font_fallbacks"); | ||
1042 | font_sizestr = eina_stringshare_add("font_size"); | ||
1043 | font_sourcestr = eina_stringshare_add("font_source"); | ||
1044 | font_weightstr = eina_stringshare_add("font_weight"); | ||
1045 | font_stylestr = eina_stringshare_add("font_style"); | ||
1046 | font_widthstr = eina_stringshare_add("font_width"); | ||
1047 | langstr = eina_stringshare_add("lang"); | ||
1048 | colorstr = eina_stringshare_add("color"); | ||
1049 | underline_colorstr = eina_stringshare_add("underline_color"); | ||
1050 | underline2_colorstr = eina_stringshare_add("underline2_color"); | ||
1051 | underline_dash_colorstr = eina_stringshare_add("underline_dash_color"); | ||
1052 | outline_colorstr = eina_stringshare_add("outline_color"); | ||
1053 | shadow_colorstr = eina_stringshare_add("shadow_color"); | ||
1054 | glow_colorstr = eina_stringshare_add("glow_color"); | ||
1055 | glow2_colorstr = eina_stringshare_add("glow2_color"); | ||
1056 | backing_colorstr = eina_stringshare_add("backing_color"); | ||
1057 | strikethrough_colorstr = eina_stringshare_add("strikethrough_color"); | ||
1058 | alignstr = eina_stringshare_add("align"); | ||
1059 | valignstr = eina_stringshare_add("valign"); | ||
1060 | wrapstr = eina_stringshare_add("wrap"); | ||
1061 | left_marginstr = eina_stringshare_add("left_margin"); | ||
1062 | right_marginstr = eina_stringshare_add("right_margin"); | ||
1063 | underlinestr = eina_stringshare_add("underline"); | ||
1064 | strikethroughstr = eina_stringshare_add("strikethrough"); | ||
1065 | backingstr = eina_stringshare_add("backing"); | ||
1066 | stylestr = eina_stringshare_add("style"); | ||
1067 | tabstopsstr = eina_stringshare_add("tabstops"); | ||
1068 | linesizestr = eina_stringshare_add("linesize"); | ||
1069 | linerelsizestr = eina_stringshare_add("linerelsize"); | ||
1070 | linegapstr = eina_stringshare_add("linegap"); | ||
1071 | linerelgapstr = eina_stringshare_add("linerelgap"); | ||
1072 | itemstr = eina_stringshare_add("item"); | ||
1073 | linefillstr = eina_stringshare_add("linefill"); | ||
1074 | ellipsisstr = eina_stringshare_add("ellipsis"); | ||
1075 | passwordstr = eina_stringshare_add("password"); | ||
1076 | underline_dash_widthstr = eina_stringshare_add("underline_dash_width"); | ||
1077 | underline_dash_gapstr = eina_stringshare_add("underline_dash_gap"); | ||
1078 | } | ||
1079 | format_refcount++; | ||
1080 | } | ||
1081 | |||
1082 | /** | ||
1083 | * @internal | ||
1084 | * Shutdown the format strings. | ||
1085 | */ | ||
1086 | static void | ||
1087 | _format_command_shutdown(void) | ||
1088 | { | ||
1089 | if (--format_refcount > 0) return; | ||
1090 | |||
1091 | eina_stringshare_del(fontstr); | ||
1092 | eina_stringshare_del(font_fallbacksstr); | ||
1093 | eina_stringshare_del(font_sizestr); | ||
1094 | eina_stringshare_del(font_sourcestr); | ||
1095 | eina_stringshare_del(font_weightstr); | ||
1096 | eina_stringshare_del(font_stylestr); | ||
1097 | eina_stringshare_del(font_widthstr); | ||
1098 | eina_stringshare_del(langstr); | ||
1099 | eina_stringshare_del(colorstr); | ||
1100 | eina_stringshare_del(underline_colorstr); | ||
1101 | eina_stringshare_del(underline2_colorstr); | ||
1102 | eina_stringshare_del(underline_dash_colorstr); | ||
1103 | eina_stringshare_del(outline_colorstr); | ||
1104 | eina_stringshare_del(shadow_colorstr); | ||
1105 | eina_stringshare_del(glow_colorstr); | ||
1106 | eina_stringshare_del(glow2_colorstr); | ||
1107 | eina_stringshare_del(backing_colorstr); | ||
1108 | eina_stringshare_del(strikethrough_colorstr); | ||
1109 | eina_stringshare_del(alignstr); | ||
1110 | eina_stringshare_del(valignstr); | ||
1111 | eina_stringshare_del(wrapstr); | ||
1112 | eina_stringshare_del(left_marginstr); | ||
1113 | eina_stringshare_del(right_marginstr); | ||
1114 | eina_stringshare_del(underlinestr); | ||
1115 | eina_stringshare_del(strikethroughstr); | ||
1116 | eina_stringshare_del(backingstr); | ||
1117 | eina_stringshare_del(stylestr); | ||
1118 | eina_stringshare_del(tabstopsstr); | ||
1119 | eina_stringshare_del(linesizestr); | ||
1120 | eina_stringshare_del(linerelsizestr); | ||
1121 | eina_stringshare_del(linegapstr); | ||
1122 | eina_stringshare_del(linerelgapstr); | ||
1123 | eina_stringshare_del(itemstr); | ||
1124 | eina_stringshare_del(linefillstr); | ||
1125 | eina_stringshare_del(ellipsisstr); | ||
1126 | eina_stringshare_del(passwordstr); | ||
1127 | eina_stringshare_del(underline_dash_widthstr); | ||
1128 | eina_stringshare_del(underline_dash_gapstr); | ||
1129 | } | ||
1130 | |||
1131 | /** | ||
1132 | * @internal | ||
1133 | * Copies str to dst while removing the \\ char, i.e unescape the escape sequences. | ||
1134 | * | ||
1135 | * @param[out] dst the destination string - Should not be NULL. | ||
1136 | * @param[in] src the source string - Should not be NULL. | ||
1137 | */ | ||
1138 | static void | ||
1139 | _format_clean_param(char *dst, const char *src) | ||
1140 | { | ||
1141 | const char *ss; | ||
1142 | char *ds; | ||
1143 | |||
1144 | ds = dst; | ||
1145 | for (ss = src; *ss; ss++, ds++) | ||
1146 | { | ||
1147 | if ((*ss == '\\') && *(ss + 1)) ss++; | ||
1148 | *ds = *ss; | ||
1149 | } | ||
1150 | *ds = 0; | ||
1151 | } | ||
1152 | |||
1153 | /** | ||
1154 | * @internal | ||
1155 | * Parses the cmd and parameter and adds the parsed format to fmt. | ||
1156 | * | ||
1157 | * @param obj the evas object - should not be NULL. | ||
1158 | * @param fmt The format to populate - should not be NULL. | ||
1159 | * @param[in] cmd the command to process, should be stringshared. | ||
1160 | * @param[in] param the parameter of the command. | ||
1161 | */ | ||
1162 | static void | ||
1163 | _format_command(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *cmd, const char *param) | ||
1164 | { | ||
1165 | int len; | ||
1166 | char *tmp_param; | ||
1167 | |||
1168 | len = strlen(param); | ||
1169 | tmp_param = alloca(len + 1); | ||
1170 | |||
1171 | _format_clean_param(tmp_param, param); | ||
1172 | |||
1173 | /* If we are changing the font, create the fdesc. */ | ||
1174 | if ((cmd == font_weightstr) || (cmd == font_widthstr) || | ||
1175 | (cmd == font_stylestr) || (cmd == langstr) || | ||
1176 | (cmd == fontstr) || (cmd == font_fallbacksstr)) | ||
1177 | { | ||
1178 | if (!fmt->font.fdesc) | ||
1179 | { | ||
1180 | fmt->font.fdesc = evas_font_desc_new(); | ||
1181 | } | ||
1182 | else if (!fmt->font.fdesc->is_new) | ||
1183 | { | ||
1184 | Evas_Font_Description *old = fmt->font.fdesc; | ||
1185 | fmt->font.fdesc = evas_font_desc_dup(fmt->font.fdesc); | ||
1186 | if (old) evas_font_desc_unref(old); | ||
1187 | } | ||
1188 | } | ||
1189 | |||
1190 | |||
1191 | if (cmd == fontstr) | ||
1192 | { | ||
1193 | evas_font_name_parse(fmt->font.fdesc, tmp_param); | ||
1194 | } | ||
1195 | else if (cmd == font_fallbacksstr) | ||
1196 | { | ||
1197 | eina_stringshare_replace(&(fmt->font.fdesc->fallbacks), tmp_param); | ||
1198 | } | ||
1199 | else if (cmd == font_sizestr) | ||
1200 | { | ||
1201 | int v; | ||
1202 | |||
1203 | v = atoi(tmp_param); | ||
1204 | if (v != fmt->font.size) | ||
1205 | { | ||
1206 | fmt->font.size = v; | ||
1207 | } | ||
1208 | } | ||
1209 | else if (cmd == font_sourcestr) | ||
1210 | { | ||
1211 | if ((!fmt->font.source) || | ||
1212 | ((fmt->font.source) && (strcmp(fmt->font.source, tmp_param)))) | ||
1213 | { | ||
1214 | if (fmt->font.source) eina_stringshare_del(fmt->font.source); | ||
1215 | fmt->font.source = eina_stringshare_add(tmp_param); | ||
1216 | } | ||
1217 | } | ||
1218 | else if (cmd == font_weightstr) | ||
1219 | { | ||
1220 | fmt->font.fdesc->weight = evas_font_style_find(tmp_param, | ||
1221 | tmp_param + strlen(tmp_param), EVAS_FONT_STYLE_WEIGHT); | ||
1222 | } | ||
1223 | else if (cmd == font_stylestr) | ||
1224 | { | ||
1225 | fmt->font.fdesc->slant = evas_font_style_find(tmp_param, | ||
1226 | tmp_param + strlen(tmp_param), EVAS_FONT_STYLE_SLANT); | ||
1227 | } | ||
1228 | else if (cmd == font_widthstr) | ||
1229 | { | ||
1230 | fmt->font.fdesc->width = evas_font_style_find(tmp_param, | ||
1231 | tmp_param + strlen(tmp_param), EVAS_FONT_STYLE_WIDTH); | ||
1232 | } | ||
1233 | else if (cmd == langstr) | ||
1234 | { | ||
1235 | eina_stringshare_replace(&(fmt->font.fdesc->lang), tmp_param); | ||
1236 | } | ||
1237 | else if (cmd == colorstr) | ||
1238 | _format_color_parse(tmp_param, | ||
1239 | &(fmt->color.normal.r), &(fmt->color.normal.g), | ||
1240 | &(fmt->color.normal.b), &(fmt->color.normal.a)); | ||
1241 | else if (cmd == underline_colorstr) | ||
1242 | _format_color_parse(tmp_param, | ||
1243 | &(fmt->color.underline.r), &(fmt->color.underline.g), | ||
1244 | &(fmt->color.underline.b), &(fmt->color.underline.a)); | ||
1245 | else if (cmd == underline2_colorstr) | ||
1246 | _format_color_parse(tmp_param, | ||
1247 | &(fmt->color.underline2.r), &(fmt->color.underline2.g), | ||
1248 | &(fmt->color.underline2.b), &(fmt->color.underline2.a)); | ||
1249 | else if (cmd == underline_dash_colorstr) | ||
1250 | _format_color_parse(tmp_param, | ||
1251 | &(fmt->color.underline_dash.r), &(fmt->color.underline_dash.g), | ||
1252 | &(fmt->color.underline_dash.b), &(fmt->color.underline_dash.a)); | ||
1253 | else if (cmd == outline_colorstr) | ||
1254 | _format_color_parse(tmp_param, | ||
1255 | &(fmt->color.outline.r), &(fmt->color.outline.g), | ||
1256 | &(fmt->color.outline.b), &(fmt->color.outline.a)); | ||
1257 | else if (cmd == shadow_colorstr) | ||
1258 | _format_color_parse(tmp_param, | ||
1259 | &(fmt->color.shadow.r), &(fmt->color.shadow.g), | ||
1260 | &(fmt->color.shadow.b), &(fmt->color.shadow.a)); | ||
1261 | else if (cmd == glow_colorstr) | ||
1262 | _format_color_parse(tmp_param, | ||
1263 | &(fmt->color.glow.r), &(fmt->color.glow.g), | ||
1264 | &(fmt->color.glow.b), &(fmt->color.glow.a)); | ||
1265 | else if (cmd == glow2_colorstr) | ||
1266 | _format_color_parse(tmp_param, | ||
1267 | &(fmt->color.glow2.r), &(fmt->color.glow2.g), | ||
1268 | &(fmt->color.glow2.b), &(fmt->color.glow2.a)); | ||
1269 | else if (cmd == backing_colorstr) | ||
1270 | _format_color_parse(tmp_param, | ||
1271 | &(fmt->color.backing.r), &(fmt->color.backing.g), | ||
1272 | &(fmt->color.backing.b), &(fmt->color.backing.a)); | ||
1273 | else if (cmd == strikethrough_colorstr) | ||
1274 | _format_color_parse(tmp_param, | ||
1275 | &(fmt->color.strikethrough.r), &(fmt->color.strikethrough.g), | ||
1276 | &(fmt->color.strikethrough.b), &(fmt->color.strikethrough.a)); | ||
1277 | else if (cmd == alignstr) | ||
1278 | { | ||
1279 | if (!strcmp(tmp_param, "auto")) | ||
1280 | { | ||
1281 | fmt->halign_auto = EINA_TRUE; | ||
1282 | } | ||
1283 | else | ||
1284 | { | ||
1285 | if (!strcmp(tmp_param, "middle")) fmt->halign = 0.5; | ||
1286 | else if (!strcmp(tmp_param, "center")) fmt->halign = 0.5; | ||
1287 | else if (!strcmp(tmp_param, "left")) fmt->halign = 0.0; | ||
1288 | else if (!strcmp(tmp_param, "right")) fmt->halign = 1.0; | ||
1289 | else | ||
1290 | { | ||
1291 | char *endptr = NULL; | ||
1292 | double val = strtod(tmp_param, &endptr); | ||
1293 | if (endptr) | ||
1294 | { | ||
1295 | while (*endptr && _is_white(*endptr)) | ||
1296 | endptr++; | ||
1297 | if (*endptr == '%') | ||
1298 | val /= 100.0; | ||
1299 | } | ||
1300 | fmt->halign = val; | ||
1301 | if (fmt->halign < 0.0) fmt->halign = 0.0; | ||
1302 | else if (fmt->halign > 1.0) fmt->halign = 1.0; | ||
1303 | } | ||
1304 | fmt->halign_auto = EINA_FALSE; | ||
1305 | } | ||
1306 | } | ||
1307 | else if (cmd == valignstr) | ||
1308 | { | ||
1309 | if (!strcmp(tmp_param, "top")) fmt->valign = 0.0; | ||
1310 | else if (!strcmp(tmp_param, "middle")) fmt->valign = 0.5; | ||
1311 | else if (!strcmp(tmp_param, "center")) fmt->valign = 0.5; | ||
1312 | else if (!strcmp(tmp_param, "bottom")) fmt->valign = 1.0; | ||
1313 | else if (!strcmp(tmp_param, "baseline")) fmt->valign = -1.0; | ||
1314 | else if (!strcmp(tmp_param, "base")) fmt->valign = -1.0; | ||
1315 | else | ||
1316 | { | ||
1317 | char *endptr = NULL; | ||
1318 | double val = strtod(tmp_param, &endptr); | ||
1319 | if (endptr) | ||
1320 | { | ||
1321 | while (*endptr && _is_white(*endptr)) | ||
1322 | endptr++; | ||
1323 | if (*endptr == '%') | ||
1324 | val /= 100.0; | ||
1325 | } | ||
1326 | fmt->valign = val; | ||
1327 | if (fmt->valign < 0.0) fmt->valign = 0.0; | ||
1328 | else if (fmt->valign > 1.0) fmt->valign = 1.0; | ||
1329 | } | ||
1330 | } | ||
1331 | else if (cmd == wrapstr) | ||
1332 | { | ||
1333 | if (!strcmp(tmp_param, "word")) | ||
1334 | { | ||
1335 | fmt->wrap_word = 1; | ||
1336 | fmt->wrap_char = fmt->wrap_mixed = 0; | ||
1337 | } | ||
1338 | else if (!strcmp(tmp_param, "char")) | ||
1339 | { | ||
1340 | fmt->wrap_word = fmt->wrap_mixed = 0; | ||
1341 | fmt->wrap_char = 1; | ||
1342 | } | ||
1343 | else if (!strcmp(tmp_param, "mixed")) | ||
1344 | { | ||
1345 | fmt->wrap_word = fmt->wrap_char = 0; | ||
1346 | fmt->wrap_mixed = 1; | ||
1347 | } | ||
1348 | else | ||
1349 | { | ||
1350 | fmt->wrap_word = fmt->wrap_mixed = fmt->wrap_char = 0; | ||
1351 | } | ||
1352 | } | ||
1353 | else if (cmd == left_marginstr) | ||
1354 | { | ||
1355 | if (!strcmp(tmp_param, "reset")) | ||
1356 | fmt->margin.l = 0; | ||
1357 | else | ||
1358 | { | ||
1359 | if (tmp_param[0] == '+') | ||
1360 | fmt->margin.l += atoi(&(tmp_param[1])); | ||
1361 | else if (tmp_param[0] == '-') | ||
1362 | fmt->margin.l -= atoi(&(tmp_param[1])); | ||
1363 | else | ||
1364 | fmt->margin.l = atoi(tmp_param); | ||
1365 | if (fmt->margin.l < 0) fmt->margin.l = 0; | ||
1366 | } | ||
1367 | } | ||
1368 | else if (cmd == right_marginstr) | ||
1369 | { | ||
1370 | if (!strcmp(tmp_param, "reset")) | ||
1371 | fmt->margin.r = 0; | ||
1372 | else | ||
1373 | { | ||
1374 | if (tmp_param[0] == '+') | ||
1375 | fmt->margin.r += atoi(&(tmp_param[1])); | ||
1376 | else if (tmp_param[0] == '-') | ||
1377 | fmt->margin.r -= atoi(&(tmp_param[1])); | ||
1378 | else | ||
1379 | fmt->margin.r = atoi(tmp_param); | ||
1380 | if (fmt->margin.r < 0) fmt->margin.r = 0; | ||
1381 | } | ||
1382 | } | ||
1383 | else if (cmd == underlinestr) | ||
1384 | { | ||
1385 | if (!strcmp(tmp_param, "off")) | ||
1386 | { | ||
1387 | fmt->underline = 0; | ||
1388 | fmt->underline2 = 0; | ||
1389 | } | ||
1390 | else if ((!strcmp(tmp_param, "on")) || | ||
1391 | (!strcmp(tmp_param, "single"))) | ||
1392 | { | ||
1393 | fmt->underline = 1; | ||
1394 | fmt->underline2 = 0; | ||
1395 | } | ||
1396 | else if (!strcmp(tmp_param, "double")) | ||
1397 | { | ||
1398 | fmt->underline = 1; | ||
1399 | fmt->underline2 = 1; | ||
1400 | } | ||
1401 | else if (!strcmp(tmp_param, "dashed")) | ||
1402 | fmt->underline_dash = 1; | ||
1403 | } | ||
1404 | else if (cmd == strikethroughstr) | ||
1405 | { | ||
1406 | if (!strcmp(tmp_param, "off")) | ||
1407 | fmt->strikethrough = 0; | ||
1408 | else if (!strcmp(tmp_param, "on")) | ||
1409 | fmt->strikethrough = 1; | ||
1410 | } | ||
1411 | else if (cmd == backingstr) | ||
1412 | { | ||
1413 | if (!strcmp(tmp_param, "off")) | ||
1414 | fmt->backing = 0; | ||
1415 | else if (!strcmp(tmp_param, "on")) | ||
1416 | fmt->backing = 1; | ||
1417 | } | ||
1418 | else if (cmd == stylestr) | ||
1419 | { | ||
1420 | char *p1, *p2, *p, *pp; | ||
1421 | |||
1422 | p1 = alloca(len + 1); | ||
1423 | *p1 = 0; | ||
1424 | p2 = alloca(len + 1); | ||
1425 | *p2 = 0; | ||
1426 | /* no comma */ | ||
1427 | if (!strstr(tmp_param, ",")) p1 = tmp_param; | ||
1428 | else | ||
1429 | { | ||
1430 | /* split string "str1,str2" into p1 and p2 (if we have more than | ||
1431 | * 1 str2 eg "str1,str2,str3,str4" then we don't care. p2 just | ||
1432 | * ends up being the last one as right now it's only valid to have | ||
1433 | * 1 comma and 2 strings */ | ||
1434 | pp = p1; | ||
1435 | for (p = tmp_param; *p; p++) | ||
1436 | { | ||
1437 | if (*p == ',') | ||
1438 | { | ||
1439 | *pp = 0; | ||
1440 | pp = p2; | ||
1441 | continue; | ||
1442 | } | ||
1443 | *pp = *p; | ||
1444 | pp++; | ||
1445 | } | ||
1446 | *pp = 0; | ||
1447 | } | ||
1448 | if (!strcmp(p1, "off")) fmt->style = EVAS_TEXT_STYLE_PLAIN; | ||
1449 | else if (!strcmp(p1, "none")) fmt->style = EVAS_TEXT_STYLE_PLAIN; | ||
1450 | else if (!strcmp(p1, "plain")) fmt->style = EVAS_TEXT_STYLE_PLAIN; | ||
1451 | else if (!strcmp(p1, "shadow")) fmt->style = EVAS_TEXT_STYLE_SHADOW; | ||
1452 | else if (!strcmp(p1, "outline")) fmt->style = EVAS_TEXT_STYLE_OUTLINE; | ||
1453 | else if (!strcmp(p1, "soft_outline")) fmt->style = EVAS_TEXT_STYLE_SOFT_OUTLINE; | ||
1454 | else if (!strcmp(p1, "outline_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SHADOW; | ||
1455 | else if (!strcmp(p1, "outline_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW; | ||
1456 | else if (!strcmp(p1, "glow")) fmt->style = EVAS_TEXT_STYLE_GLOW; | ||
1457 | else if (!strcmp(p1, "far_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SHADOW; | ||
1458 | else if (!strcmp(p1, "soft_shadow")) fmt->style = EVAS_TEXT_STYLE_SOFT_SHADOW; | ||
1459 | else if (!strcmp(p1, "far_soft_shadow")) fmt->style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW; | ||
1460 | else fmt->style = EVAS_TEXT_STYLE_PLAIN; | ||
1461 | |||
1462 | if (*p2) | ||
1463 | { | ||
1464 | if (!strcmp(p2, "bottom_right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT); | ||
1465 | else if (!strcmp(p2, "bottom")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM); | ||
1466 | else if (!strcmp(p2, "bottom_left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT); | ||
1467 | else if (!strcmp(p2, "left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT); | ||
1468 | else if (!strcmp(p2, "top_left")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT); | ||
1469 | else if (!strcmp(p2, "top")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP); | ||
1470 | else if (!strcmp(p2, "top_right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT); | ||
1471 | else if (!strcmp(p2, "right")) EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT); | ||
1472 | else EVAS_TEXT_STYLE_SHADOW_DIRECTION_SET(fmt->style, EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT); | ||
1473 | } | ||
1474 | } | ||
1475 | else if (cmd == tabstopsstr) | ||
1476 | { | ||
1477 | fmt->tabstops = atoi(tmp_param); | ||
1478 | if (fmt->tabstops < 1) fmt->tabstops = 1; | ||
1479 | } | ||
1480 | else if (cmd == linesizestr) | ||
1481 | { | ||
1482 | fmt->linesize = atoi(tmp_param); | ||
1483 | fmt->linerelsize = 0.0; | ||
1484 | } | ||
1485 | else if (cmd == linerelsizestr) | ||
1486 | { | ||
1487 | char *endptr = NULL; | ||
1488 | double val = strtod(tmp_param, &endptr); | ||
1489 | if (endptr) | ||
1490 | { | ||
1491 | while (*endptr && _is_white(*endptr)) | ||
1492 | endptr++; | ||
1493 | if (*endptr == '%') | ||
1494 | { | ||
1495 | fmt->linerelsize = val / 100.0; | ||
1496 | fmt->linesize = 0; | ||
1497 | if (fmt->linerelsize < 0.0) fmt->linerelsize = 0.0; | ||
1498 | } | ||
1499 | } | ||
1500 | } | ||
1501 | else if (cmd == linegapstr) | ||
1502 | { | ||
1503 | fmt->linegap = atoi(tmp_param); | ||
1504 | fmt->linerelgap = 0.0; | ||
1505 | } | ||
1506 | else if (cmd == linerelgapstr) | ||
1507 | { | ||
1508 | char *endptr = NULL; | ||
1509 | double val = strtod(tmp_param, &endptr); | ||
1510 | if (endptr) | ||
1511 | { | ||
1512 | while (*endptr && _is_white(*endptr)) | ||
1513 | endptr++; | ||
1514 | if (*endptr == '%') | ||
1515 | { | ||
1516 | fmt->linerelgap = val / 100.0; | ||
1517 | fmt->linegap = 0; | ||
1518 | if (fmt->linerelgap < 0.0) fmt->linerelgap = 0.0; | ||
1519 | } | ||
1520 | } | ||
1521 | } | ||
1522 | else if (cmd == itemstr) | ||
1523 | { | ||
1524 | // itemstr == replacement object items in textblock - inline imges | ||
1525 | // for example | ||
1526 | } | ||
1527 | else if (cmd == linefillstr) | ||
1528 | { | ||
1529 | char *endptr = NULL; | ||
1530 | double val = strtod(tmp_param, &endptr); | ||
1531 | if (endptr) | ||
1532 | { | ||
1533 | while (*endptr && _is_white(*endptr)) | ||
1534 | endptr++; | ||
1535 | if (*endptr == '%') | ||
1536 | { | ||
1537 | fmt->linefill = val / 100.0; | ||
1538 | if (fmt->linefill < 0.0) fmt->linefill = 0.0; | ||
1539 | } | ||
1540 | } | ||
1541 | } | ||
1542 | else if (cmd == ellipsisstr) | ||
1543 | { | ||
1544 | char *endptr = NULL; | ||
1545 | fmt->ellipsis = strtod(tmp_param, &endptr); | ||
1546 | if ((fmt->ellipsis < 0.0) || (fmt->ellipsis > 1.0)) | ||
1547 | fmt->ellipsis = -1.0; | ||
1548 | else | ||
1549 | { | ||
1550 | Evas_Object_Textblock *o; | ||
1551 | |||
1552 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
1553 | o->have_ellipsis = 1; | ||
1554 | } | ||
1555 | } | ||
1556 | else if (cmd == passwordstr) | ||
1557 | { | ||
1558 | if (!strcmp(tmp_param, "off")) | ||
1559 | fmt->password = 0; | ||
1560 | else if (!strcmp(tmp_param, "on")) | ||
1561 | fmt->password = 1; | ||
1562 | } | ||
1563 | else if (cmd == underline_dash_widthstr) | ||
1564 | { | ||
1565 | fmt->underline_dash_width = atoi(tmp_param); | ||
1566 | if (fmt->underline_dash_width <= 0) fmt->underline_dash_width = 1; | ||
1567 | } | ||
1568 | else if (cmd == underline_dash_gapstr) | ||
1569 | { | ||
1570 | fmt->underline_dash_gap = atoi(tmp_param); | ||
1571 | if (fmt->underline_dash_gap <= 0) fmt->underline_dash_gap = 1; | ||
1572 | } | ||
1573 | } | ||
1574 | |||
1575 | /** | ||
1576 | * @internal | ||
1577 | * Returns #EINA_TRUE if the item is a format parameter, #EINA_FALSE otherwise. | ||
1578 | * | ||
1579 | * @param[in] item the item to check - Not NULL. | ||
1580 | */ | ||
1581 | static Eina_Bool | ||
1582 | _format_is_param(const char *item) | ||
1583 | { | ||
1584 | if (strchr(item, '=')) return EINA_TRUE; | ||
1585 | return EINA_FALSE; | ||
1586 | } | ||
1587 | |||
1588 | /** | ||
1589 | * @internal | ||
1590 | * Parse the format item and populate key and val with the stringshares that | ||
1591 | * corrospond to the formats parsed. | ||
1592 | * It expects item to be of the structure: | ||
1593 | * "key=val" | ||
1594 | * | ||
1595 | * @param[in] item the item to parse - Not NULL. | ||
1596 | * @param[out] key where to store the key at - Not NULL. | ||
1597 | * @param[out] val where to store the value at - Not NULL. | ||
1598 | */ | ||
1599 | static void | ||
1600 | _format_param_parse(const char *item, const char **key, const char **val) | ||
1601 | { | ||
1602 | const char *start, *end, *quote; | ||
1603 | |||
1604 | start = strchr(item, '='); | ||
1605 | *key = eina_stringshare_add_length(item, start - item); | ||
1606 | start++; /* Advance after the '=' */ | ||
1607 | /* If we can find a quote, our new delimiter is a quote, not a space. */ | ||
1608 | if ((quote = strchr(start, '\''))) | ||
1609 | { | ||
1610 | start = quote + 1; | ||
1611 | end = strchr(start, '\''); | ||
1612 | } | ||
1613 | else | ||
1614 | { | ||
1615 | end = strchr(start, ' '); | ||
1616 | } | ||
1617 | |||
1618 | /* Null terminate before the spaces */ | ||
1619 | if (end) | ||
1620 | { | ||
1621 | *val = eina_stringshare_add_length(start, end - start); | ||
1622 | } | ||
1623 | else | ||
1624 | { | ||
1625 | *val = eina_stringshare_add(start); | ||
1626 | } | ||
1627 | } | ||
1628 | |||
1629 | /** | ||
1630 | * @internal | ||
1631 | * This function parses the format passed in *s and advances s to point to the | ||
1632 | * next format item, while returning the current one as the return value. | ||
1633 | * @param s The current and returned position in the format string. | ||
1634 | * @return the current item parsed from the string. | ||
1635 | */ | ||
1636 | static const char * | ||
1637 | _format_parse(const char **s) | ||
1638 | { | ||
1639 | const char *p; | ||
1640 | const char *s1 = NULL, *s2 = NULL; | ||
1641 | Eina_Bool quote = EINA_FALSE;; | ||
1642 | |||
1643 | p = *s; | ||
1644 | if (*p == 0) return NULL; | ||
1645 | for (;;) | ||
1646 | { | ||
1647 | if (!s1) | ||
1648 | { | ||
1649 | if (*p != ' ') s1 = p; | ||
1650 | if (*p == 0) break; | ||
1651 | } | ||
1652 | else if (!s2) | ||
1653 | { | ||
1654 | if (*p == '\'') | ||
1655 | { | ||
1656 | quote = !quote; | ||
1657 | } | ||
1658 | |||
1659 | if ((p > *s) && (p[-1] != '\\') && (!quote)) | ||
1660 | { | ||
1661 | if (*p == ' ') s2 = p; | ||
1662 | } | ||
1663 | if (*p == 0) s2 = p; | ||
1664 | } | ||
1665 | p++; | ||
1666 | if (s1 && s2) | ||
1667 | { | ||
1668 | *s = s2; | ||
1669 | return s1; | ||
1670 | } | ||
1671 | } | ||
1672 | *s = p; | ||
1673 | return NULL; | ||
1674 | } | ||
1675 | |||
1676 | /** | ||
1677 | * @internal | ||
1678 | * Parse the format str and populate fmt with the formats found. | ||
1679 | * | ||
1680 | * @param obj The evas object - Not NULL. | ||
1681 | * @param[out] fmt The format to populate - Not NULL. | ||
1682 | * @param[in] str the string to parse.- Not NULL. | ||
1683 | */ | ||
1684 | static void | ||
1685 | _format_fill(Evas_Object *obj, Evas_Object_Textblock_Format *fmt, const char *str) | ||
1686 | { | ||
1687 | const char *s; | ||
1688 | const char *item; | ||
1689 | |||
1690 | s = str; | ||
1691 | |||
1692 | /* get rid of anything +s or -s off the start of the string */ | ||
1693 | while ((*s == ' ') || (*s == '+') || (*s == '-')) s++; | ||
1694 | |||
1695 | while ((item = _format_parse(&s))) | ||
1696 | { | ||
1697 | if (_format_is_param(item)) | ||
1698 | { | ||
1699 | const char *key = NULL, *val = NULL; | ||
1700 | |||
1701 | _format_param_parse(item, &key, &val); | ||
1702 | _format_command(obj, fmt, key, val); | ||
1703 | eina_stringshare_del(key); | ||
1704 | eina_stringshare_del(val); | ||
1705 | } | ||
1706 | else | ||
1707 | { | ||
1708 | /* immediate - not handled here */ | ||
1709 | } | ||
1710 | } | ||
1711 | } | ||
1712 | |||
1713 | /** | ||
1714 | * @internal | ||
1715 | * Duplicate a format and return the duplicate. | ||
1716 | * | ||
1717 | * @param obj The evas object - Not NULL. | ||
1718 | * @param[in] fmt The format to duplicate - Not NULL. | ||
1719 | * @return the copy of the format. | ||
1720 | */ | ||
1721 | static Evas_Object_Textblock_Format * | ||
1722 | _format_dup(Evas_Object *obj, const Evas_Object_Textblock_Format *fmt) | ||
1723 | { | ||
1724 | Evas_Object_Textblock_Format *fmt2; | ||
1725 | |||
1726 | fmt2 = calloc(1, sizeof(Evas_Object_Textblock_Format)); | ||
1727 | memcpy(fmt2, fmt, sizeof(Evas_Object_Textblock_Format)); | ||
1728 | fmt2->ref = 1; | ||
1729 | fmt2->font.fdesc = evas_font_desc_ref(fmt->font.fdesc); | ||
1730 | |||
1731 | if (fmt->font.source) fmt2->font.source = eina_stringshare_add(fmt->font.source); | ||
1732 | |||
1733 | /* FIXME: just ref the font here... */ | ||
1734 | fmt2->font.font = evas_font_load(obj->layer->evas, fmt2->font.fdesc, | ||
1735 | fmt2->font.source, (int)(((double) fmt2->font.size) * obj->cur.scale)); | ||
1736 | return fmt2; | ||
1737 | } | ||
1738 | |||
1739 | |||
1740 | |||
1741 | |||
1742 | /** | ||
1743 | * @internal | ||
1744 | * @typedef Ctxt | ||
1745 | * | ||
1746 | * A pack of information that needed to be passed around in the layout engine, | ||
1747 | * packed for easier access. | ||
1748 | */ | ||
1749 | typedef struct _Ctxt Ctxt; | ||
1750 | |||
1751 | struct _Ctxt | ||
1752 | { | ||
1753 | Evas_Object *obj; | ||
1754 | Evas_Object_Textblock *o; | ||
1755 | |||
1756 | Evas_Object_Textblock_Paragraph *paragraphs; | ||
1757 | Evas_Object_Textblock_Paragraph *par; | ||
1758 | Evas_Object_Textblock_Line *ln; | ||
1759 | |||
1760 | |||
1761 | Eina_List *format_stack; | ||
1762 | Evas_Object_Textblock_Format *fmt; | ||
1763 | |||
1764 | int x, y; | ||
1765 | int w, h; | ||
1766 | int wmax, hmax; | ||
1767 | int maxascent, maxdescent; | ||
1768 | int marginl, marginr; | ||
1769 | int line_no; | ||
1770 | int underline_extend; | ||
1771 | int have_underline, have_underline2; | ||
1772 | double align, valign; | ||
1773 | Eina_Bool align_auto : 1; | ||
1774 | Eina_Bool width_changed : 1; | ||
1775 | }; | ||
1776 | |||
1777 | static void _layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Text_Item *ti, Eina_List *rel); | ||
1778 | static void _text_item_update_sizes(Ctxt *c, Evas_Object_Textblock_Text_Item *ti); | ||
1779 | static void _layout_do_format(const Evas_Object *obj, Ctxt *c, Evas_Object_Textblock_Format **_fmt, Evas_Object_Textblock_Node_Format *n, int *style_pad_l, int *style_pad_r, int *style_pad_t, int *style_pad_b, Eina_Bool create_item); | ||
1780 | /** | ||
1781 | * @internal | ||
1782 | * Adjust the ascent/descent of the format and context. | ||
1783 | * | ||
1784 | * @param maxascent The ascent to update - Not NUL. | ||
1785 | * @param maxdescent The descent to update - Not NUL. | ||
1786 | * @param fmt The format to adjust - NOT NULL. | ||
1787 | */ | ||
1788 | static void | ||
1789 | _layout_format_ascent_descent_adjust(const Evas_Object *obj, | ||
1790 | Evas_Coord *maxascent, Evas_Coord *maxdescent, | ||
1791 | Evas_Object_Textblock_Format *fmt) | ||
1792 | { | ||
1793 | int ascent, descent; | ||
1794 | |||
1795 | if (fmt->font.font) | ||
1796 | { | ||
1797 | // ascent = c->ENFN->font_max_ascent_get(c->ENDT, fmt->font.font); | ||
1798 | // descent = c->ENFN->font_max_descent_get(c->ENDT, fmt->font.font); | ||
1799 | ascent = ENFN->font_ascent_get(ENDT, fmt->font.font); | ||
1800 | descent = ENFN->font_descent_get(ENDT, fmt->font.font); | ||
1801 | if (fmt->linesize > 0) | ||
1802 | { | ||
1803 | if ((ascent + descent) < fmt->linesize) | ||
1804 | { | ||
1805 | ascent = ((fmt->linesize * ascent) / (ascent + descent)); | ||
1806 | descent = fmt->linesize - ascent; | ||
1807 | } | ||
1808 | } | ||
1809 | else if (fmt->linerelsize > 0.0) | ||
1810 | { | ||
1811 | descent = descent * fmt->linerelsize; | ||
1812 | ascent = ascent * fmt->linerelsize; | ||
1813 | } | ||
1814 | descent += fmt->linegap; | ||
1815 | descent += ((ascent + descent) * fmt->linerelgap); | ||
1816 | if (*maxascent < ascent) *maxascent = ascent; | ||
1817 | if (*maxdescent < descent) *maxdescent = descent; | ||
1818 | if (fmt->linefill > 0.0) | ||
1819 | { | ||
1820 | int dh; | ||
1821 | |||
1822 | dh = obj->cur.geometry.h - (*maxascent + *maxdescent); | ||
1823 | if (dh < 0) dh = 0; | ||
1824 | dh = fmt->linefill * dh; | ||
1825 | *maxdescent += dh / 2; | ||
1826 | *maxascent += dh - (dh / 2); | ||
1827 | // FIXME: set flag that says "if heigh changes - reformat" | ||
1828 | } | ||
1829 | } | ||
1830 | } | ||
1831 | |||
1832 | /** | ||
1833 | * @internal | ||
1834 | * Create a new line using the info from the format and update the format | ||
1835 | * and context. | ||
1836 | * | ||
1837 | * @param c The context to work on - Not NULL. | ||
1838 | * @param fmt The format to use info from - NOT NULL. | ||
1839 | */ | ||
1840 | static void | ||
1841 | _layout_line_new(Ctxt *c, Evas_Object_Textblock_Format *fmt) | ||
1842 | { | ||
1843 | c->ln = calloc(1, sizeof(Evas_Object_Textblock_Line)); | ||
1844 | c->align = fmt->halign; | ||
1845 | c->align_auto = fmt->halign_auto; | ||
1846 | c->marginl = fmt->margin.l; | ||
1847 | c->marginr = fmt->margin.r; | ||
1848 | c->par->lines = (Evas_Object_Textblock_Line *)eina_inlist_append(EINA_INLIST_GET(c->par->lines), EINA_INLIST_GET(c->ln)); | ||
1849 | c->x = 0; | ||
1850 | c->maxascent = c->maxdescent = 0; | ||
1851 | c->ln->line_no = -1; | ||
1852 | c->ln->par = c->par; | ||
1853 | } | ||
1854 | |||
1855 | static inline Evas_Object_Textblock_Paragraph * | ||
1856 | _layout_find_paragraph_by_y(Evas_Object_Textblock *o, Evas_Coord y) | ||
1857 | { | ||
1858 | Evas_Object_Textblock_Paragraph *start, *par; | ||
1859 | int i; | ||
1860 | |||
1861 | start = o->paragraphs; | ||
1862 | |||
1863 | for (i = 0 ; i < TEXTBLOCK_PAR_INDEX_SIZE ; i++) | ||
1864 | { | ||
1865 | if (!o->par_index[i] || (o->par_index[i]->y > y)) | ||
1866 | { | ||
1867 | break; | ||
1868 | } | ||
1869 | start = o->par_index[i]; | ||
1870 | } | ||
1871 | |||
1872 | EINA_INLIST_FOREACH(start, par) | ||
1873 | { | ||
1874 | if ((par->y <= y) && (y < par->y + par->h)) | ||
1875 | return par; | ||
1876 | } | ||
1877 | |||
1878 | return NULL; | ||
1879 | } | ||
1880 | |||
1881 | static inline Evas_Object_Textblock_Paragraph * | ||
1882 | _layout_find_paragraph_by_line_no(Evas_Object_Textblock *o, int line_no) | ||
1883 | { | ||
1884 | Evas_Object_Textblock_Paragraph *start, *par; | ||
1885 | int i; | ||
1886 | |||
1887 | start = o->paragraphs; | ||
1888 | |||
1889 | for (i = 0 ; i < TEXTBLOCK_PAR_INDEX_SIZE ; i++) | ||
1890 | { | ||
1891 | if (!o->par_index[i] || (o->par_index[i]->line_no > line_no)) | ||
1892 | { | ||
1893 | break; | ||
1894 | } | ||
1895 | start = o->par_index[i]; | ||
1896 | } | ||
1897 | |||
1898 | EINA_INLIST_FOREACH(start, par) | ||
1899 | { | ||
1900 | Evas_Object_Textblock_Paragraph *npar = | ||
1901 | (Evas_Object_Textblock_Paragraph *) EINA_INLIST_GET(par)->next; | ||
1902 | if ((par->line_no <= line_no) && | ||
1903 | (!npar || (line_no < npar->line_no))) | ||
1904 | return par; | ||
1905 | } | ||
1906 | |||
1907 | return NULL; | ||
1908 | } | ||
1909 | /* End of rbtree index functios */ | ||
1910 | |||
1911 | /** | ||
1912 | * @internal | ||
1913 | * Create a new layout paragraph. | ||
1914 | * If c->par is not NULL, the paragraph is appended/prepended according | ||
1915 | * to the append parameter. If it is NULL, the paragraph is appended at | ||
1916 | * the end of the list. | ||
1917 | * | ||
1918 | * @param c The context to work on - Not NULL. | ||
1919 | * @param n the associated text node | ||
1920 | * @param append true to append, false to prpend. | ||
1921 | */ | ||
1922 | static void | ||
1923 | _layout_paragraph_new(Ctxt *c, Evas_Object_Textblock_Node_Text *n, | ||
1924 | Eina_Bool append) | ||
1925 | { | ||
1926 | Evas_Object_Textblock_Paragraph *rel_par = c->par; | ||
1927 | c->par = calloc(1, sizeof(Evas_Object_Textblock_Paragraph)); | ||
1928 | if (append || !rel_par) | ||
1929 | c->paragraphs = (Evas_Object_Textblock_Paragraph *) | ||
1930 | eina_inlist_append_relative(EINA_INLIST_GET(c->paragraphs), | ||
1931 | EINA_INLIST_GET(c->par), | ||
1932 | EINA_INLIST_GET(rel_par)); | ||
1933 | else | ||
1934 | c->paragraphs = (Evas_Object_Textblock_Paragraph *) | ||
1935 | eina_inlist_prepend_relative(EINA_INLIST_GET(c->paragraphs), | ||
1936 | EINA_INLIST_GET(c->par), | ||
1937 | EINA_INLIST_GET(rel_par)); | ||
1938 | |||
1939 | c->ln = NULL; | ||
1940 | c->par->text_node = n; | ||
1941 | if (n) | ||
1942 | n->par = c->par; | ||
1943 | c->par->line_no = -1; | ||
1944 | c->par->visible = 1; | ||
1945 | c->o->num_paragraphs++; | ||
1946 | } | ||
1947 | |||
1948 | #ifdef BIDI_SUPPORT | ||
1949 | /** | ||
1950 | * @internal | ||
1951 | * Update bidi paragraph props. | ||
1952 | * | ||
1953 | * @param par The paragraph to update | ||
1954 | */ | ||
1955 | static inline void | ||
1956 | _layout_update_bidi_props(const Evas_Object_Textblock *o, | ||
1957 | Evas_Object_Textblock_Paragraph *par) | ||
1958 | { | ||
1959 | if (par->text_node) | ||
1960 | { | ||
1961 | const Eina_Unicode *text; | ||
1962 | int *segment_idxs = NULL; | ||
1963 | text = eina_ustrbuf_string_get(par->text_node->unicode); | ||
1964 | |||
1965 | if (o->bidi_delimiters) | ||
1966 | segment_idxs = evas_bidi_segment_idxs_get(text, o->bidi_delimiters); | ||
1967 | |||
1968 | evas_bidi_paragraph_props_unref(par->bidi_props); | ||
1969 | par->bidi_props = evas_bidi_paragraph_props_get(text, | ||
1970 | eina_ustrbuf_length_get(par->text_node->unicode), | ||
1971 | segment_idxs); | ||
1972 | par->direction = EVAS_BIDI_PARAGRAPH_DIRECTION_IS_RTL(par->bidi_props) ? | ||
1973 | EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR; | ||
1974 | par->is_bidi = !!par->bidi_props; | ||
1975 | if (segment_idxs) free(segment_idxs); | ||
1976 | } | ||
1977 | } | ||
1978 | #endif | ||
1979 | |||
1980 | |||
1981 | /** | ||
1982 | * @internal | ||
1983 | * Free the visual lines in the paragraph (logical items are kept) | ||
1984 | */ | ||
1985 | static void | ||
1986 | _paragraph_clear(const Evas_Object *obj __UNUSED__, | ||
1987 | Evas_Object_Textblock_Paragraph *par) | ||
1988 | { | ||
1989 | while (par->lines) | ||
1990 | { | ||
1991 | Evas_Object_Textblock_Line *ln; | ||
1992 | |||
1993 | ln = (Evas_Object_Textblock_Line *) par->lines; | ||
1994 | par->lines = (Evas_Object_Textblock_Line *)eina_inlist_remove(EINA_INLIST_GET(par->lines), EINA_INLIST_GET(par->lines)); | ||
1995 | _line_free(ln); | ||
1996 | } | ||
1997 | } | ||
1998 | |||
1999 | /** | ||
2000 | * @internal | ||
2001 | * Free the layout paragraph and all of it's lines and logical items. | ||
2002 | */ | ||
2003 | static void | ||
2004 | _paragraph_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *par) | ||
2005 | { | ||
2006 | Evas_Object_Textblock *o; | ||
2007 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
2008 | _paragraph_clear(obj, par); | ||
2009 | |||
2010 | { | ||
2011 | Eina_List *i, *i_prev; | ||
2012 | Evas_Object_Textblock_Item *it; | ||
2013 | EINA_LIST_FOREACH_SAFE(par->logical_items, i, i_prev, it) | ||
2014 | { | ||
2015 | _item_free(obj, NULL, it); | ||
2016 | } | ||
2017 | eina_list_free(par->logical_items); | ||
2018 | } | ||
2019 | #ifdef BIDI_SUPPORT | ||
2020 | if (par->bidi_props) | ||
2021 | evas_bidi_paragraph_props_unref(par->bidi_props); | ||
2022 | #endif | ||
2023 | /* If we are the active par of the text node, set to NULL */ | ||
2024 | if (par->text_node && (par->text_node->par == par)) | ||
2025 | par->text_node->par = NULL; | ||
2026 | |||
2027 | o->num_paragraphs--; | ||
2028 | |||
2029 | free(par); | ||
2030 | } | ||
2031 | |||
2032 | /** | ||
2033 | * @internal | ||
2034 | * Clear all the paragraphs from the inlist pars. | ||
2035 | * | ||
2036 | * @param obj the evas object - Not NULL. | ||
2037 | * @param pars the paragraphs to clean - Not NULL. | ||
2038 | */ | ||
2039 | static void | ||
2040 | _paragraphs_clear(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars) | ||
2041 | { | ||
2042 | Evas_Object_Textblock_Paragraph *par; | ||
2043 | |||
2044 | EINA_INLIST_FOREACH(EINA_INLIST_GET(pars), par) | ||
2045 | { | ||
2046 | _paragraph_clear(obj, par); | ||
2047 | } | ||
2048 | } | ||
2049 | |||
2050 | /** | ||
2051 | * @internal | ||
2052 | * Free the paragraphs from the inlist pars, the difference between this and | ||
2053 | * _paragraphs_clear is that the latter keeps the logical items and the par | ||
2054 | * items, while the former frees them as well. | ||
2055 | * | ||
2056 | * @param obj the evas object - Not NULL. | ||
2057 | * @param pars the paragraphs to clean - Not NULL. | ||
2058 | */ | ||
2059 | static void | ||
2060 | _paragraphs_free(const Evas_Object *obj, Evas_Object_Textblock_Paragraph *pars) | ||
2061 | { | ||
2062 | Evas_Object_Textblock *o; | ||
2063 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
2064 | |||
2065 | o->num_paragraphs = 0; | ||
2066 | |||
2067 | while (pars) | ||
2068 | { | ||
2069 | Evas_Object_Textblock_Paragraph *par; | ||
2070 | |||
2071 | par = (Evas_Object_Textblock_Paragraph *) pars; | ||
2072 | pars = (Evas_Object_Textblock_Paragraph *)eina_inlist_remove(EINA_INLIST_GET(pars), EINA_INLIST_GET(par)); | ||
2073 | _paragraph_free(obj, par); | ||
2074 | } | ||
2075 | } | ||
2076 | |||
2077 | /** | ||
2078 | * @internal | ||
2079 | * Push fmt to the format stack, if fmt is NULL, will fush a default item. | ||
2080 | * | ||
2081 | * @param c the context to work on - Not NULL. | ||
2082 | * @param fmt the format to push. | ||
2083 | * @see _layout_format_pop() | ||
2084 | */ | ||
2085 | static Evas_Object_Textblock_Format * | ||
2086 | _layout_format_push(Ctxt *c, Evas_Object_Textblock_Format *fmt, | ||
2087 | Evas_Object_Textblock_Node_Format *fnode) | ||
2088 | { | ||
2089 | if (fmt) | ||
2090 | { | ||
2091 | fmt = _format_dup(c->obj, fmt); | ||
2092 | c->format_stack = eina_list_prepend(c->format_stack, fmt); | ||
2093 | fmt->fnode = fnode; | ||
2094 | } | ||
2095 | else | ||
2096 | { | ||
2097 | fmt = calloc(1, sizeof(Evas_Object_Textblock_Format)); | ||
2098 | c->format_stack = eina_list_prepend(c->format_stack, fmt); | ||
2099 | fmt->ref = 1; | ||
2100 | fmt->halign = 0.0; | ||
2101 | fmt->halign_auto = EINA_TRUE; | ||
2102 | fmt->valign = -1.0; | ||
2103 | fmt->style = EVAS_TEXT_STYLE_PLAIN; | ||
2104 | fmt->tabstops = 32; | ||
2105 | fmt->linesize = 0; | ||
2106 | fmt->linerelsize = 0.0; | ||
2107 | fmt->linegap = 0; | ||
2108 | fmt->underline_dash_width = 6; | ||
2109 | fmt->underline_dash_gap = 2; | ||
2110 | fmt->linerelgap = 0.0; | ||
2111 | fmt->password = 1; | ||
2112 | } | ||
2113 | return fmt; | ||
2114 | } | ||
2115 | |||
2116 | /** | ||
2117 | * @internal | ||
2118 | * Pop fmt to the format stack, if there's something in the stack free fmt | ||
2119 | * and set it to point to the next item instead, else return fmt. | ||
2120 | * | ||
2121 | * @param c the context to work on - Not NULL. | ||
2122 | * @param format - the text of the format to free (assured to start with '-'). | ||
2123 | * @return the next format in the stack, or format if there's none. | ||
2124 | * @see _layout_format_push() | ||
2125 | */ | ||
2126 | static Evas_Object_Textblock_Format * | ||
2127 | _layout_format_pop(Ctxt *c, const char *format) | ||
2128 | { | ||
2129 | Evas_Object_Textblock_Format *fmt = eina_list_data_get(c->format_stack); | ||
2130 | |||
2131 | if ((c->format_stack) && (c->format_stack->next)) | ||
2132 | { | ||
2133 | Eina_List *redo_nodes = NULL; | ||
2134 | format++; /* Skip the '-' */ | ||
2135 | |||
2136 | /* Generic pop, should just pop. */ | ||
2137 | if (((format[0] == ' ') && !format[1]) || | ||
2138 | !format[0]) | ||
2139 | { | ||
2140 | _format_unref_free(c->obj, fmt); | ||
2141 | c->format_stack = | ||
2142 | eina_list_remove_list(c->format_stack, c->format_stack); | ||
2143 | } | ||
2144 | else | ||
2145 | { | ||
2146 | size_t len = strlen(format); | ||
2147 | Eina_List *i, *i_next; | ||
2148 | /* Remove only the matching format. */ | ||
2149 | EINA_LIST_FOREACH_SAFE(c->format_stack, i, i_next, fmt) | ||
2150 | { | ||
2151 | /* Stop when we reach the base item */ | ||
2152 | if (!i_next) | ||
2153 | break; | ||
2154 | |||
2155 | c->format_stack = | ||
2156 | eina_list_remove_list(c->format_stack, c->format_stack); | ||
2157 | |||
2158 | /* Make sure the ending tag matches the starting tag. | ||
2159 | * I.e whole of the ending tag matches the start of the | ||
2160 | * starting tag, and the starting tag's next char is either | ||
2161 | * NULL or white. Skip the starting '+'. */ | ||
2162 | if (_FORMAT_IS_CLOSER_OF( | ||
2163 | fmt->fnode->orig_format, format, len)) | ||
2164 | { | ||
2165 | _format_unref_free(c->obj, fmt); | ||
2166 | break; | ||
2167 | } | ||
2168 | else | ||
2169 | { | ||
2170 | redo_nodes = eina_list_prepend(redo_nodes, fmt->fnode); | ||
2171 | _format_unref_free(c->obj, fmt); | ||
2172 | } | ||
2173 | } | ||
2174 | } | ||
2175 | |||
2176 | /* Redo all the nodes needed to be redone */ | ||
2177 | { | ||
2178 | Evas_Object_Textblock_Node_Format *fnode; | ||
2179 | Eina_List *i, *i_next; | ||
2180 | |||
2181 | EINA_LIST_FOREACH_SAFE(redo_nodes, i, i_next, fnode) | ||
2182 | { | ||
2183 | /* FIXME: Actually do something with the new acquired padding, | ||
2184 | * the can be different and affect our padding! */ | ||
2185 | Evas_Coord style_pad_l, style_pad_r, style_pad_t, style_pad_b; | ||
2186 | style_pad_l = style_pad_r = style_pad_t = style_pad_b = 0; | ||
2187 | redo_nodes = eina_list_remove_list(redo_nodes, i); | ||
2188 | fmt = eina_list_data_get(c->format_stack); | ||
2189 | _layout_do_format(c->obj, c, &fmt, fnode, | ||
2190 | &style_pad_l, &style_pad_r, | ||
2191 | &style_pad_t, &style_pad_b, EINA_FALSE); | ||
2192 | } | ||
2193 | } | ||
2194 | |||
2195 | fmt = eina_list_data_get(c->format_stack); | ||
2196 | } | ||
2197 | return fmt; | ||
2198 | } | ||
2199 | |||
2200 | /** | ||
2201 | * @internal | ||
2202 | * Parse item and fill fmt with the item. | ||
2203 | * | ||
2204 | * @param c the context to work on - Not NULL. | ||
2205 | * @param fmt the format to fill - not null. | ||
2206 | */ | ||
2207 | static void | ||
2208 | _layout_format_value_handle(Ctxt *c, Evas_Object_Textblock_Format *fmt, const char *item) | ||
2209 | { | ||
2210 | const char *key = NULL, *val = NULL; | ||
2211 | |||
2212 | _format_param_parse(item, &key, &val); | ||
2213 | if ((key) && (val)) _format_command(c->obj, fmt, key, val); | ||
2214 | if (key) eina_stringshare_del(key); | ||
2215 | if (val) eina_stringshare_del(val); | ||
2216 | c->align = fmt->halign; | ||
2217 | c->align_auto = fmt->halign_auto; | ||
2218 | c->marginl = fmt->margin.l; | ||
2219 | c->marginr = fmt->margin.r; | ||
2220 | } | ||
2221 | |||
2222 | #define VSIZE_FULL 0 | ||
2223 | #define VSIZE_ASCENT 1 | ||
2224 | |||
2225 | #define SIZE 0 | ||
2226 | #define SIZE_ABS 1 | ||
2227 | #define SIZE_REL 2 | ||
2228 | |||
2229 | /** | ||
2230 | * @internal | ||
2231 | * Get the current line's alignment from the context. | ||
2232 | * | ||
2233 | * @param c the context to work on - Not NULL. | ||
2234 | */ | ||
2235 | static inline double | ||
2236 | _layout_line_align_get(Ctxt *c) | ||
2237 | { | ||
2238 | #ifdef BIDI_SUPPORT | ||
2239 | if (c->align_auto && c->ln) | ||
2240 | { | ||
2241 | if (c->ln->items && c->ln->items->text_node && | ||
2242 | (c->ln->par->direction == EVAS_BIDI_DIRECTION_RTL)) | ||
2243 | { | ||
2244 | /* Align right*/ | ||
2245 | return 1.0; | ||
2246 | } | ||
2247 | else | ||
2248 | { | ||
2249 | /* Align left */ | ||
2250 | return 0.0; | ||
2251 | } | ||
2252 | } | ||
2253 | #endif | ||
2254 | return c->align; | ||
2255 | } | ||
2256 | |||
2257 | #ifdef BIDI_SUPPORT | ||
2258 | /** | ||
2259 | * @internal | ||
2260 | * Reorder the items in visual order | ||
2261 | * | ||
2262 | * @param line the line to reorder | ||
2263 | */ | ||
2264 | static void | ||
2265 | _layout_line_reorder(Evas_Object_Textblock_Line *line) | ||
2266 | { | ||
2267 | /*FIXME: do it a bit more efficient - not very efficient ATM. */ | ||
2268 | Evas_Object_Textblock_Item *it; | ||
2269 | EvasBiDiStrIndex *v_to_l = NULL; | ||
2270 | Evas_Coord x; | ||
2271 | size_t start, end; | ||
2272 | size_t len; | ||
2273 | |||
2274 | if (line->items && line->items->text_node && | ||
2275 | line->par->bidi_props) | ||
2276 | { | ||
2277 | Evas_BiDi_Paragraph_Props *props; | ||
2278 | props = line->par->bidi_props; | ||
2279 | start = end = line->items->text_pos; | ||
2280 | |||
2281 | /* Find the first and last positions in the line */ | ||
2282 | |||
2283 | EINA_INLIST_FOREACH(line->items, it) | ||
2284 | { | ||
2285 | if (it->text_pos < start) | ||
2286 | { | ||
2287 | start = it->text_pos; | ||
2288 | } | ||
2289 | else | ||
2290 | { | ||
2291 | int tlen; | ||
2292 | tlen = (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? | ||
2293 | _ITEM_TEXT(it)->text_props.text_len : 1; | ||
2294 | if (it->text_pos + tlen > end) | ||
2295 | { | ||
2296 | end = it->text_pos + tlen; | ||
2297 | } | ||
2298 | } | ||
2299 | } | ||
2300 | |||
2301 | len = end - start; | ||
2302 | evas_bidi_props_reorder_line(NULL, start, len, props, &v_to_l); | ||
2303 | |||
2304 | /* Update visual pos */ | ||
2305 | { | ||
2306 | Evas_Object_Textblock_Item *i; | ||
2307 | i = line->items; | ||
2308 | while (i) | ||
2309 | { | ||
2310 | i->visual_pos = evas_bidi_position_logical_to_visual( | ||
2311 | v_to_l, len, i->text_pos - start); | ||
2312 | i = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(i)->next; | ||
2313 | } | ||
2314 | } | ||
2315 | |||
2316 | /*FIXME: not very efficient, sort the items arrays. Anyhow, should only | ||
2317 | * reorder if it's a bidi paragraph */ | ||
2318 | { | ||
2319 | Evas_Object_Textblock_Item *i, *j, *min; | ||
2320 | i = line->items; | ||
2321 | while (i) | ||
2322 | { | ||
2323 | min = i; | ||
2324 | EINA_INLIST_FOREACH(i, j) | ||
2325 | { | ||
2326 | if (j->visual_pos < min->visual_pos) | ||
2327 | { | ||
2328 | min = j; | ||
2329 | } | ||
2330 | } | ||
2331 | if (min != i) | ||
2332 | { | ||
2333 | line->items = (Evas_Object_Textblock_Item *) eina_inlist_remove(EINA_INLIST_GET(line->items), EINA_INLIST_GET(min)); | ||
2334 | line->items = (Evas_Object_Textblock_Item *) eina_inlist_prepend_relative(EINA_INLIST_GET(line->items), EINA_INLIST_GET(min), EINA_INLIST_GET(i)); | ||
2335 | } | ||
2336 | |||
2337 | i = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(min)->next; | ||
2338 | } | ||
2339 | } | ||
2340 | } | ||
2341 | |||
2342 | if (v_to_l) free(v_to_l); | ||
2343 | x = 0; | ||
2344 | EINA_INLIST_FOREACH(line->items, it) | ||
2345 | { | ||
2346 | it->x = x; | ||
2347 | x += it->adv; | ||
2348 | } | ||
2349 | } | ||
2350 | #endif | ||
2351 | |||
2352 | /* FIXME: doc */ | ||
2353 | static void | ||
2354 | _layout_calculate_format_item_size(const Evas_Object *obj, | ||
2355 | const Evas_Object_Textblock_Format_Item *fi, | ||
2356 | Evas_Coord *maxascent, Evas_Coord *maxdescent, | ||
2357 | Evas_Coord *_y, Evas_Coord *_w, Evas_Coord *_h) | ||
2358 | { | ||
2359 | /* Adjust sizes according to current line height/scale */ | ||
2360 | Evas_Coord w, h; | ||
2361 | const char *p, *s; | ||
2362 | |||
2363 | s = fi->item; | ||
2364 | w = fi->parent.w; | ||
2365 | h = fi->parent.h; | ||
2366 | switch (fi->size) | ||
2367 | { | ||
2368 | case SIZE: | ||
2369 | p = strstr(s, " size="); | ||
2370 | if (p) | ||
2371 | { | ||
2372 | p += 6; | ||
2373 | if (sscanf(p, "%ix%i", &w, &h) == 2) | ||
2374 | { | ||
2375 | w = w * obj->cur.scale; | ||
2376 | h = h * obj->cur.scale; | ||
2377 | } | ||
2378 | } | ||
2379 | break; | ||
2380 | case SIZE_REL: | ||
2381 | p = strstr((char *) s, " relsize="); | ||
2382 | p += 9; | ||
2383 | if (sscanf(p, "%ix%i", &w, &h) == 2) | ||
2384 | { | ||
2385 | int sz = 1; | ||
2386 | if (fi->vsize == VSIZE_FULL) | ||
2387 | { | ||
2388 | sz = *maxdescent + *maxascent; | ||
2389 | } | ||
2390 | else if (fi->vsize == VSIZE_ASCENT) | ||
2391 | { | ||
2392 | sz = *maxascent; | ||
2393 | } | ||
2394 | w = (w * sz) / h; | ||
2395 | h = sz; | ||
2396 | } | ||
2397 | break; | ||
2398 | case SIZE_ABS: | ||
2399 | /* Nothing to do */ | ||
2400 | default: | ||
2401 | break; | ||
2402 | } | ||
2403 | |||
2404 | switch (fi->size) | ||
2405 | { | ||
2406 | case SIZE: | ||
2407 | case SIZE_ABS: | ||
2408 | switch (fi->vsize) | ||
2409 | { | ||
2410 | case VSIZE_FULL: | ||
2411 | if (h > (*maxdescent + *maxascent)) | ||
2412 | { | ||
2413 | *maxascent += h - (*maxdescent + *maxascent); | ||
2414 | *_y = -*maxascent; | ||
2415 | } | ||
2416 | else | ||
2417 | *_y = -(h - *maxdescent); | ||
2418 | break; | ||
2419 | case VSIZE_ASCENT: | ||
2420 | if (h > *maxascent) | ||
2421 | { | ||
2422 | *maxascent = h; | ||
2423 | *_y = -h; | ||
2424 | } | ||
2425 | else | ||
2426 | *_y = -h; | ||
2427 | break; | ||
2428 | default: | ||
2429 | break; | ||
2430 | } | ||
2431 | break; | ||
2432 | case SIZE_REL: | ||
2433 | switch (fi->vsize) | ||
2434 | { | ||
2435 | case VSIZE_FULL: | ||
2436 | case VSIZE_ASCENT: | ||
2437 | *_y = -*maxascent; | ||
2438 | break; | ||
2439 | default: | ||
2440 | break; | ||
2441 | } | ||
2442 | break; | ||
2443 | default: | ||
2444 | break; | ||
2445 | } | ||
2446 | |||
2447 | *_w = w; | ||
2448 | *_h = h; | ||
2449 | } | ||
2450 | |||
2451 | /** | ||
2452 | * @internal | ||
2453 | * Order the items in the line, update it's properties and update it's | ||
2454 | * corresponding paragraph. | ||
2455 | * | ||
2456 | * @param c the context to work on - Not NULL. | ||
2457 | * @param fmt the format to use. | ||
2458 | * @param add_line true if we should create a line, false otherwise. | ||
2459 | */ | ||
2460 | static void | ||
2461 | _layout_line_finalize(Ctxt *c, Evas_Object_Textblock_Format *fmt) | ||
2462 | { | ||
2463 | Evas_Object_Textblock_Item *it; | ||
2464 | Evas_Coord x = 0; | ||
2465 | |||
2466 | /* If there are no text items yet, calc ascent/descent | ||
2467 | * according to the current format. */ | ||
2468 | if (c->maxascent + c->maxdescent == 0) | ||
2469 | _layout_format_ascent_descent_adjust(c->obj, &c->maxascent, | ||
2470 | &c->maxdescent, fmt); | ||
2471 | |||
2472 | /* Adjust all the item sizes according to the final line size, | ||
2473 | * and update the x positions of all the items of the line. */ | ||
2474 | EINA_INLIST_FOREACH(c->ln->items, it) | ||
2475 | { | ||
2476 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) | ||
2477 | { | ||
2478 | Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it); | ||
2479 | if (!fi->formatme) goto loop_advance; | ||
2480 | _layout_calculate_format_item_size(c->obj, fi, &c->maxascent, | ||
2481 | &c->maxdescent, &fi->y, &fi->parent.w, &fi->parent.h); | ||
2482 | fi->parent.adv = fi->parent.w; | ||
2483 | } | ||
2484 | |||
2485 | loop_advance: | ||
2486 | it->x = x; | ||
2487 | x += it->adv; | ||
2488 | |||
2489 | if ((it->x + it->adv) > c->ln->w) c->ln->w = it->x + it->adv; | ||
2490 | } | ||
2491 | |||
2492 | c->ln->y = (c->y - c->par->y) + c->o->style_pad.t; | ||
2493 | c->ln->h = c->maxascent + c->maxdescent; | ||
2494 | c->ln->baseline = c->maxascent; | ||
2495 | if (c->have_underline2) | ||
2496 | { | ||
2497 | if (c->maxdescent < 4) c->underline_extend = 4 - c->maxdescent; | ||
2498 | } | ||
2499 | else if (c->have_underline) | ||
2500 | { | ||
2501 | if (c->maxdescent < 2) c->underline_extend = 2 - c->maxdescent; | ||
2502 | } | ||
2503 | c->ln->line_no = c->line_no - c->ln->par->line_no; | ||
2504 | c->line_no++; | ||
2505 | c->y += c->maxascent + c->maxdescent; | ||
2506 | if (c->w >= 0) | ||
2507 | { | ||
2508 | c->ln->x = c->marginl + c->o->style_pad.l + | ||
2509 | ((c->w - c->ln->w - | ||
2510 | c->o->style_pad.l - c->o->style_pad.r - | ||
2511 | c->marginl - c->marginr) * _layout_line_align_get(c)); | ||
2512 | } | ||
2513 | else | ||
2514 | { | ||
2515 | c->ln->x = c->marginl + c->o->style_pad.l; | ||
2516 | } | ||
2517 | |||
2518 | c->par->h = c->ln->y + c->ln->h; | ||
2519 | if (c->ln->w > c->par->w) | ||
2520 | c->par->w = c->ln->w; | ||
2521 | |||
2522 | { | ||
2523 | Evas_Coord new_wmax = c->ln->w + | ||
2524 | c->marginl + c->marginr - (c->o->style_pad.l + c->o->style_pad.r); | ||
2525 | if (new_wmax > c->wmax) | ||
2526 | c->wmax = new_wmax; | ||
2527 | } | ||
2528 | } | ||
2529 | |||
2530 | /** | ||
2531 | * @internal | ||
2532 | * Create a new line and append it to the lines in the context. | ||
2533 | * | ||
2534 | * @param c the context to work on - Not NULL. | ||
2535 | * @param fmt the format to use. | ||
2536 | * @param add_line true if we should create a line, false otherwise. | ||
2537 | */ | ||
2538 | static void | ||
2539 | _layout_line_advance(Ctxt *c, Evas_Object_Textblock_Format *fmt) | ||
2540 | { | ||
2541 | _layout_line_finalize(c, fmt); | ||
2542 | _layout_line_new(c, fmt); | ||
2543 | } | ||
2544 | |||
2545 | /** | ||
2546 | * @internal | ||
2547 | * Create a new text layout item from the string and the format. | ||
2548 | * | ||
2549 | * @param c the context to work on - Not NULL. | ||
2550 | * @param fmt the format to use. | ||
2551 | * @param str the string to use. | ||
2552 | * @param len the length of the string. | ||
2553 | */ | ||
2554 | static Evas_Object_Textblock_Text_Item * | ||
2555 | _layout_text_item_new(Ctxt *c __UNUSED__, Evas_Object_Textblock_Format *fmt) | ||
2556 | { | ||
2557 | Evas_Object_Textblock_Text_Item *ti; | ||
2558 | |||
2559 | ti = calloc(1, sizeof(Evas_Object_Textblock_Text_Item)); | ||
2560 | ti->parent.format = fmt; | ||
2561 | ti->parent.format->ref++; | ||
2562 | ti->parent.type = EVAS_TEXTBLOCK_ITEM_TEXT; | ||
2563 | return ti; | ||
2564 | } | ||
2565 | |||
2566 | /** | ||
2567 | * @internal | ||
2568 | * Return the cutoff of the text in the text item. | ||
2569 | * | ||
2570 | * @param c the context to work on - Not NULL. | ||
2571 | * @param fmt the format to use. - Not NULL. | ||
2572 | * @param it the item to check - Not null. | ||
2573 | * @return -1 if there is no cutoff (either because there is really none, | ||
2574 | * or because of an error), cutoff index on success. | ||
2575 | */ | ||
2576 | static int | ||
2577 | _layout_text_cutoff_get(Ctxt *c, Evas_Object_Textblock_Format *fmt, | ||
2578 | const Evas_Object_Textblock_Text_Item *ti) | ||
2579 | { | ||
2580 | if (fmt->font.font) | ||
2581 | { | ||
2582 | Evas_Coord x; | ||
2583 | x = c->w - c->o->style_pad.l - c->o->style_pad.r - c->marginl - | ||
2584 | c->marginr - c->x - ti->x_adjustment; | ||
2585 | if (x < 0) | ||
2586 | x = 0; | ||
2587 | return c->ENFN->font_last_up_to_pos(c->ENDT, fmt->font.font, | ||
2588 | &ti->text_props, x, 0); | ||
2589 | } | ||
2590 | return -1; | ||
2591 | } | ||
2592 | |||
2593 | /** | ||
2594 | * @internal | ||
2595 | * Split before cut, and strip if str[cut - 1] is a whitespace. | ||
2596 | * | ||
2597 | * @param c the context to work on - Not NULL. | ||
2598 | * @param ti the item to cut - not null. | ||
2599 | * @param lti the logical list item of the item. | ||
2600 | * @param cut the cut index. | ||
2601 | * @return the second (newly created) item. | ||
2602 | */ | ||
2603 | static Evas_Object_Textblock_Text_Item * | ||
2604 | _layout_item_text_split_strip_white(Ctxt *c, | ||
2605 | Evas_Object_Textblock_Text_Item *ti, Eina_List *lti, size_t cut) | ||
2606 | { | ||
2607 | const Eina_Unicode *ts; | ||
2608 | Evas_Object_Textblock_Text_Item *new_ti = NULL, *white_ti = NULL; | ||
2609 | |||
2610 | ts = GET_ITEM_TEXT(ti); | ||
2611 | |||
2612 | if (!IS_AT_END(ti, cut) && (ti->text_props.text_len > 0)) | ||
2613 | { | ||
2614 | new_ti = _layout_text_item_new(c, ti->parent.format); | ||
2615 | new_ti->parent.text_node = ti->parent.text_node; | ||
2616 | new_ti->parent.text_pos = ti->parent.text_pos + cut; | ||
2617 | new_ti->parent.merge = EINA_TRUE; | ||
2618 | |||
2619 | evas_common_text_props_split(&ti->text_props, | ||
2620 | &new_ti->text_props, cut); | ||
2621 | _layout_text_add_logical_item(c, new_ti, lti); | ||
2622 | } | ||
2623 | |||
2624 | /* Strip the previous white if needed */ | ||
2625 | if ((cut >= 1) && _is_white(ts[cut - 1]) && (ti->text_props.text_len > 0)) | ||
2626 | { | ||
2627 | if (cut - 1 > 0) | ||
2628 | { | ||
2629 | size_t white_cut = cut - 1; | ||
2630 | white_ti = _layout_text_item_new(c, ti->parent.format); | ||
2631 | white_ti->parent.text_node = ti->parent.text_node; | ||
2632 | white_ti->parent.text_pos = ti->parent.text_pos + white_cut; | ||
2633 | white_ti->parent.merge = EINA_TRUE; | ||
2634 | white_ti->parent.visually_deleted = EINA_TRUE; | ||
2635 | |||
2636 | evas_common_text_props_split(&ti->text_props, | ||
2637 | &white_ti->text_props, white_cut); | ||
2638 | _layout_text_add_logical_item(c, white_ti, lti); | ||
2639 | } | ||
2640 | else | ||
2641 | { | ||
2642 | /* Mark this one as the visually deleted. */ | ||
2643 | ti->parent.visually_deleted = EINA_TRUE; | ||
2644 | } | ||
2645 | } | ||
2646 | |||
2647 | if (new_ti || white_ti) | ||
2648 | { | ||
2649 | _text_item_update_sizes(c, ti); | ||
2650 | } | ||
2651 | return new_ti; | ||
2652 | } | ||
2653 | |||
2654 | /** | ||
2655 | * @internal | ||
2656 | * Merge item2 into item1 and free item2. | ||
2657 | * | ||
2658 | * @param c the context to work on - Not NULL. | ||
2659 | * @param item1 the item to copy to | ||
2660 | * @param item2 the item to copy from | ||
2661 | */ | ||
2662 | static void | ||
2663 | _layout_item_merge_and_free(Ctxt *c, | ||
2664 | Evas_Object_Textblock_Text_Item *item1, | ||
2665 | Evas_Object_Textblock_Text_Item *item2) | ||
2666 | { | ||
2667 | evas_common_text_props_merge(&item1->text_props, | ||
2668 | &item2->text_props); | ||
2669 | |||
2670 | _text_item_update_sizes(c, item1); | ||
2671 | |||
2672 | item1->parent.merge = EINA_FALSE; | ||
2673 | item1->parent.visually_deleted = EINA_FALSE; | ||
2674 | |||
2675 | _item_free(c->obj, NULL, _ITEM(item2)); | ||
2676 | } | ||
2677 | |||
2678 | /** | ||
2679 | * @internal | ||
2680 | * Calculates an item's size. | ||
2681 | * | ||
2682 | * @param c the context | ||
2683 | * @param it the item itself. | ||
2684 | */ | ||
2685 | static void | ||
2686 | _text_item_update_sizes(Ctxt *c, Evas_Object_Textblock_Text_Item *ti) | ||
2687 | { | ||
2688 | int tw, th, inset, advw; | ||
2689 | const Evas_Object_Textblock_Format *fmt = ti->parent.format; | ||
2690 | int shad_sz = 0, shad_dst = 0, out_sz = 0; | ||
2691 | int dx = 0, minx = 0, maxx = 0, shx1, shx2; | ||
2692 | |||
2693 | tw = th = 0; | ||
2694 | if (fmt->font.font) | ||
2695 | c->ENFN->font_string_size_get(c->ENDT, fmt->font.font, | ||
2696 | &ti->text_props, &tw, &th); | ||
2697 | inset = 0; | ||
2698 | if (fmt->font.font) | ||
2699 | inset = c->ENFN->font_inset_get(c->ENDT, fmt->font.font, | ||
2700 | &ti->text_props); | ||
2701 | advw = 0; | ||
2702 | if (fmt->font.font) | ||
2703 | advw = c->ENFN->font_h_advance_get(c->ENDT, fmt->font.font, | ||
2704 | &ti->text_props); | ||
2705 | |||
2706 | |||
2707 | /* These adjustments are calculated and thus heavily linked to those in | ||
2708 | * textblock_render!!! Don't change one without the other. */ | ||
2709 | |||
2710 | switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC) | ||
2711 | { | ||
2712 | case EVAS_TEXT_STYLE_SHADOW: | ||
2713 | shad_dst = 1; | ||
2714 | break; | ||
2715 | case EVAS_TEXT_STYLE_OUTLINE_SHADOW: | ||
2716 | case EVAS_TEXT_STYLE_FAR_SHADOW: | ||
2717 | shad_dst = 2; | ||
2718 | out_sz = 1; | ||
2719 | break; | ||
2720 | case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW: | ||
2721 | shad_dst = 1; | ||
2722 | shad_sz = 2; | ||
2723 | out_sz = 1; | ||
2724 | break; | ||
2725 | case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW: | ||
2726 | shad_dst = 2; | ||
2727 | shad_sz = 2; | ||
2728 | break; | ||
2729 | case EVAS_TEXT_STYLE_SOFT_SHADOW: | ||
2730 | shad_dst = 1; | ||
2731 | shad_sz = 2; | ||
2732 | break; | ||
2733 | case EVAS_TEXT_STYLE_GLOW: | ||
2734 | case EVAS_TEXT_STYLE_SOFT_OUTLINE: | ||
2735 | out_sz = 2; | ||
2736 | break; | ||
2737 | case EVAS_TEXT_STYLE_OUTLINE: | ||
2738 | out_sz = 1; | ||
2739 | break; | ||
2740 | default: | ||
2741 | break; | ||
2742 | } | ||
2743 | switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION) | ||
2744 | { | ||
2745 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT: | ||
2746 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT: | ||
2747 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT: | ||
2748 | dx = -1; | ||
2749 | break; | ||
2750 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT: | ||
2751 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT: | ||
2752 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT: | ||
2753 | dx = 1; | ||
2754 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP: | ||
2755 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM: | ||
2756 | default: | ||
2757 | dx = 0; | ||
2758 | break; | ||
2759 | } | ||
2760 | minx = -out_sz; | ||
2761 | maxx = out_sz; | ||
2762 | shx1 = dx * shad_dst; | ||
2763 | shx1 -= shad_sz; | ||
2764 | shx2 = dx * shad_dst; | ||
2765 | shx2 += shad_sz; | ||
2766 | if (shx1 < minx) minx = shx1; | ||
2767 | if (shx2 > maxx) maxx = shx2; | ||
2768 | inset += -minx; | ||
2769 | ti->x_adjustment = maxx - minx; | ||
2770 | |||
2771 | ti->inset = inset; | ||
2772 | ti->parent.w = tw + ti->x_adjustment; | ||
2773 | ti->parent.h = th; | ||
2774 | ti->parent.adv = advw; | ||
2775 | ti->parent.x = 0; | ||
2776 | } | ||
2777 | |||
2778 | /** | ||
2779 | * @internal | ||
2780 | * Adds the item to the list, updates the item's properties (e.g, x,w,h) | ||
2781 | * | ||
2782 | * @param c the context | ||
2783 | * @param it the item itself. | ||
2784 | * @param rel item ti will be appened after, NULL = last. | ||
2785 | */ | ||
2786 | static void | ||
2787 | _layout_text_add_logical_item(Ctxt *c, Evas_Object_Textblock_Text_Item *ti, | ||
2788 | Eina_List *rel) | ||
2789 | { | ||
2790 | _text_item_update_sizes(c, ti); | ||
2791 | |||
2792 | c->par->logical_items = eina_list_append_relative_list( | ||
2793 | c->par->logical_items, ti, rel); | ||
2794 | } | ||
2795 | |||
2796 | /** | ||
2797 | * @internal | ||
2798 | * Appends the text from node n starting at start ending at off to the layout. | ||
2799 | * It uses the fmt for the formatting. | ||
2800 | * | ||
2801 | * @param c the current context- NOT NULL. | ||
2802 | * @param fmt the format to use. | ||
2803 | * @param n the text node. - Not null. | ||
2804 | * @param start the start position. - in range. | ||
2805 | * @param off the offset - start + offset in range. if offset is -1, it'll add everything to the end of the string if offset = 0 it'll return with doing nothing. | ||
2806 | * @param repch a replacement char to print instead of the original string, for example, * when working with passwords. | ||
2807 | */ | ||
2808 | static void | ||
2809 | _layout_text_append(Ctxt *c, Evas_Object_Textblock_Format *fmt, Evas_Object_Textblock_Node_Text *n, int start, int off, const char *repch) | ||
2810 | { | ||
2811 | const Eina_Unicode *str = EINA_UNICODE_EMPTY_STRING; | ||
2812 | const Eina_Unicode *tbase; | ||
2813 | Evas_Object_Textblock_Text_Item *ti; | ||
2814 | size_t cur_len = 0; | ||
2815 | Eina_Unicode urepch = 0; | ||
2816 | |||
2817 | /* prepare a working copy of the string, either filled by the repch or | ||
2818 | * filled with the true values */ | ||
2819 | if (n) | ||
2820 | { | ||
2821 | int len; | ||
2822 | int orig_off = off; | ||
2823 | |||
2824 | /* Figure out if we want to bail, work with an empty string, | ||
2825 | * or continue with a slice of the passed string */ | ||
2826 | len = eina_ustrbuf_length_get(n->unicode); | ||
2827 | if (off == 0) return; | ||
2828 | else if (off < 0) off = len - start; | ||
2829 | |||
2830 | if (start < 0) | ||
2831 | { | ||
2832 | start = 0; | ||
2833 | } | ||
2834 | else if ((start == 0) && (off == 0) && (orig_off == -1)) | ||
2835 | { | ||
2836 | /* Special case that means that we need to add an empty | ||
2837 | * item */ | ||
2838 | str = EINA_UNICODE_EMPTY_STRING; | ||
2839 | goto skip; | ||
2840 | } | ||
2841 | else if ((start >= len) || (start + off > len)) | ||
2842 | { | ||
2843 | return; | ||
2844 | } | ||
2845 | |||
2846 | /* If we work with a replacement char, create a string which is the same | ||
2847 | * but with replacement chars instead of regular chars. */ | ||
2848 | if ((fmt->password) && (repch) && (eina_ustrbuf_length_get(n->unicode))) | ||
2849 | { | ||
2850 | int i, ind; | ||
2851 | Eina_Unicode *ptr; | ||
2852 | |||
2853 | tbase = str = ptr = alloca((off + 1) * sizeof(Eina_Unicode)); | ||
2854 | ind = 0; | ||
2855 | urepch = eina_unicode_utf8_get_next(repch, &ind); | ||
2856 | for (i = 0 ; i < off; ptr++, i++) | ||
2857 | *ptr = urepch; | ||
2858 | *ptr = 0; | ||
2859 | } | ||
2860 | /* Use the string, just cut the relevant parts */ | ||
2861 | else | ||
2862 | { | ||
2863 | str = eina_ustrbuf_string_get(n->unicode) + start; | ||
2864 | } | ||
2865 | |||
2866 | cur_len = off; | ||
2867 | } | ||
2868 | |||
2869 | skip: | ||
2870 | tbase = str; | ||
2871 | |||
2872 | /* If there's no parent text node, only create an empty item */ | ||
2873 | if (!n) | ||
2874 | { | ||
2875 | ti = _layout_text_item_new(c, fmt); | ||
2876 | ti->parent.text_node = NULL; | ||
2877 | ti->parent.text_pos = 0; | ||
2878 | _layout_text_add_logical_item(c, ti, NULL); | ||
2879 | |||
2880 | return; | ||
2881 | } | ||
2882 | |||
2883 | while (cur_len > 0) | ||
2884 | { | ||
2885 | Evas_Font_Instance *script_fi = NULL; | ||
2886 | int script_len, tmp_cut; | ||
2887 | Evas_Script_Type script; | ||
2888 | |||
2889 | script_len = cur_len; | ||
2890 | |||
2891 | tmp_cut = evas_common_language_script_end_of_run_get(str, | ||
2892 | c->par->bidi_props, start + str - tbase, script_len); | ||
2893 | if (tmp_cut > 0) | ||
2894 | { | ||
2895 | script_len = tmp_cut; | ||
2896 | } | ||
2897 | cur_len -= script_len; | ||
2898 | |||
2899 | script = evas_common_language_script_type_get(str, script_len); | ||
2900 | |||
2901 | |||
2902 | while (script_len > 0) | ||
2903 | { | ||
2904 | Evas_Font_Instance *cur_fi = NULL; | ||
2905 | int run_len = script_len; | ||
2906 | ti = _layout_text_item_new(c, fmt); | ||
2907 | ti->parent.text_node = n; | ||
2908 | ti->parent.text_pos = start + str - tbase; | ||
2909 | |||
2910 | if (ti->parent.format->font.font) | ||
2911 | { | ||
2912 | run_len = c->ENFN->font_run_end_get(c->ENDT, | ||
2913 | ti->parent.format->font.font, &script_fi, &cur_fi, | ||
2914 | script, str, script_len); | ||
2915 | } | ||
2916 | |||
2917 | evas_common_text_props_bidi_set(&ti->text_props, | ||
2918 | c->par->bidi_props, ti->parent.text_pos); | ||
2919 | evas_common_text_props_script_set(&ti->text_props, script); | ||
2920 | |||
2921 | if (cur_fi) | ||
2922 | { | ||
2923 | c->ENFN->font_text_props_info_create(c->ENDT, | ||
2924 | cur_fi, str, &ti->text_props, c->par->bidi_props, | ||
2925 | ti->parent.text_pos, run_len); | ||
2926 | } | ||
2927 | str += run_len; | ||
2928 | script_len -= run_len; | ||
2929 | |||
2930 | _layout_text_add_logical_item(c, ti, NULL); | ||
2931 | } | ||
2932 | } | ||
2933 | } | ||
2934 | |||
2935 | /** | ||
2936 | * @internal | ||
2937 | * Add a format item from the format node n and the item item. | ||
2938 | * | ||
2939 | * @param c the current context- NOT NULL. | ||
2940 | * @param n the source format node - not null. | ||
2941 | * @param item the format text. | ||
2942 | * | ||
2943 | * @return the new format item. | ||
2944 | */ | ||
2945 | static Evas_Object_Textblock_Format_Item * | ||
2946 | _layout_format_item_add(Ctxt *c, Evas_Object_Textblock_Node_Format *n, const char *item, Evas_Object_Textblock_Format *fmt) | ||
2947 | { | ||
2948 | Evas_Object_Textblock_Format_Item *fi; | ||
2949 | |||
2950 | fi = calloc(1, sizeof(Evas_Object_Textblock_Format_Item)); | ||
2951 | fi->item = eina_stringshare_add(item); | ||
2952 | fi->parent.type = EVAS_TEXTBLOCK_ITEM_FORMAT; | ||
2953 | fi->parent.format = fmt; | ||
2954 | fi->parent.format->ref++; | ||
2955 | c->par->logical_items = eina_list_append(c->par->logical_items, fi); | ||
2956 | if (n) | ||
2957 | { | ||
2958 | fi->parent.text_node = n->text_node; | ||
2959 | /* FIXME: make it more efficient */ | ||
2960 | fi->parent.text_pos = _evas_textblock_node_format_pos_get(n); | ||
2961 | #ifdef BIDI_SUPPORT | ||
2962 | fi->bidi_dir = (evas_bidi_is_rtl_char( | ||
2963 | c->par->bidi_props, | ||
2964 | 0, | ||
2965 | fi->parent.text_pos)) ? | ||
2966 | EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR; | ||
2967 | #else | ||
2968 | fi->bidi_dir = EVAS_BIDI_DIRECTION_LTR; | ||
2969 | #endif | ||
2970 | } | ||
2971 | return fi; | ||
2972 | } | ||
2973 | |||
2974 | /** | ||
2975 | * @internal | ||
2976 | * Should be call after we finish filling a format. | ||
2977 | * FIXME: doc. | ||
2978 | */ | ||
2979 | static void | ||
2980 | _format_finalize(Evas_Object *obj, Evas_Object_Textblock_Format *fmt) | ||
2981 | { | ||
2982 | void *of; | ||
2983 | |||
2984 | of = fmt->font.font; | ||
2985 | |||
2986 | fmt->font.font = evas_font_load(obj->layer->evas, fmt->font.fdesc, | ||
2987 | fmt->font.source, (int)(((double) fmt->font.size) * obj->cur.scale)); | ||
2988 | if (of) evas_font_free(obj->layer->evas, of); | ||
2989 | } | ||
2990 | |||
2991 | /** | ||
2992 | * @internal | ||
2993 | * Returns true if the item is a tab | ||
2994 | * @def _IS_TAB(item) | ||
2995 | */ | ||
2996 | #define _IS_TAB(item) \ | ||
2997 | (!strcmp(item, "\t") || !strcmp(item, "\\t")) | ||
2998 | /** | ||
2999 | * @internal | ||
3000 | * Returns true if the item is a line spearator, false otherwise | ||
3001 | * @def _IS_LINE_SEPARATOR(item) | ||
3002 | */ | ||
3003 | #define _IS_LINE_SEPARATOR(item) \ | ||
3004 | (!strcmp(item, "\n") || !strcmp(item, "\\n")) | ||
3005 | /** | ||
3006 | * @internal | ||
3007 | * Returns true if the item is a paragraph separator, false otherwise | ||
3008 | * @def _IS_PARAGRAPH_SEPARATOR(item) | ||
3009 | */ | ||
3010 | #define _IS_PARAGRAPH_SEPARATOR(o, item) \ | ||
3011 | (!strcmp(item, "ps") || \ | ||
3012 | (o->legacy_newline && _IS_LINE_SEPARATOR(item))) /* Paragraph separator */ | ||
3013 | |||
3014 | /** | ||
3015 | * @internal | ||
3016 | * Handles a format by processing a format node. It returns the relevant format | ||
3017 | * through _fmt and updates the padding through style_pad_*. If needed, | ||
3018 | * it creates a format item. | ||
3019 | * | ||
3020 | * @param obj the evas object - NOT NULL. | ||
3021 | * @param c the current context- NOT NULL. | ||
3022 | * @param _fmt the format that holds the result. | ||
3023 | * @param n the source format node - not null. | ||
3024 | * @param style_pad_l the pad to update. | ||
3025 | * @param style_pad_r the pad to update. | ||
3026 | * @param style_pad_t the pad to update. | ||
3027 | * @param style_pad_b the pad to update. | ||
3028 | * @param create_item Create a new format item if true, only process otherwise. | ||
3029 | */ | ||
3030 | static void | ||
3031 | _layout_do_format(const Evas_Object *obj __UNUSED__, Ctxt *c, | ||
3032 | Evas_Object_Textblock_Format **_fmt, Evas_Object_Textblock_Node_Format *n, | ||
3033 | int *style_pad_l, int *style_pad_r, int *style_pad_t, int *style_pad_b, | ||
3034 | Eina_Bool create_item) | ||
3035 | { | ||
3036 | Evas_Object_Textblock_Format *fmt = *_fmt; | ||
3037 | /* FIXME: comment the algo */ | ||
3038 | |||
3039 | const char *s; | ||
3040 | const char *item; | ||
3041 | int handled = 0; | ||
3042 | |||
3043 | s = n->format; | ||
3044 | if (!strncmp(s, "+ item ", 7)) | ||
3045 | { | ||
3046 | // one of: | ||
3047 | // item size=20x10 href=name | ||
3048 | // item relsize=20x10 href=name | ||
3049 | // item abssize=20x10 href=name | ||
3050 | // | ||
3051 | // optional arguments: | ||
3052 | // vsize=full | ||
3053 | // vsize=ascent | ||
3054 | // | ||
3055 | // size == item size (modifies line size) - can be multiplied by | ||
3056 | // scale factor | ||
3057 | // relsize == relative size (height is current font height, width | ||
3058 | // modified accordingly keeping aspect) | ||
3059 | // abssize == absolute size (modifies line size) - never mulitplied by | ||
3060 | // scale factor | ||
3061 | // href == name of item - to be found and matched later and used for | ||
3062 | // positioning | ||
3063 | Evas_Object_Textblock_Format_Item *fi; | ||
3064 | int w = 1, h = 1; | ||
3065 | int vsize = 0, size = 0; | ||
3066 | char *p; | ||
3067 | |||
3068 | // don't care | ||
3069 | //href = strstr(s, " href="); | ||
3070 | p = strstr(s, " vsize="); | ||
3071 | if (p) | ||
3072 | { | ||
3073 | p += 7; | ||
3074 | if (!strncmp(p, "full", 4)) vsize = VSIZE_FULL; | ||
3075 | else if (!strncmp(p, "ascent", 6)) vsize = VSIZE_ASCENT; | ||
3076 | } | ||
3077 | p = strstr(s, " size="); | ||
3078 | if (p) | ||
3079 | { | ||
3080 | p += 6; | ||
3081 | if (sscanf(p, "%ix%i", &w, &h) == 2) | ||
3082 | { | ||
3083 | /* this is handled somewhere else because it depends | ||
3084 | * on the current scaling factor of the object which | ||
3085 | * may change and break because the results of this | ||
3086 | * function are cached */ | ||
3087 | size = SIZE; | ||
3088 | } | ||
3089 | } | ||
3090 | else | ||
3091 | { | ||
3092 | p = strstr(s, " absize="); | ||
3093 | if (p) | ||
3094 | { | ||
3095 | p += 8; | ||
3096 | if (sscanf(p, "%ix%i", &w, &h) == 2) | ||
3097 | { | ||
3098 | size = SIZE_ABS; | ||
3099 | } | ||
3100 | } | ||
3101 | else | ||
3102 | { | ||
3103 | p = strstr(s, " relsize="); | ||
3104 | if (p) | ||
3105 | { | ||
3106 | /* this is handled somewhere else because it depends | ||
3107 | * on the line it resides in, which is not defined | ||
3108 | * at this point and will change anyway, which will | ||
3109 | * break because the results of this function are | ||
3110 | * cached */ | ||
3111 | size = SIZE_REL; | ||
3112 | } | ||
3113 | } | ||
3114 | } | ||
3115 | |||
3116 | if (create_item) | ||
3117 | { | ||
3118 | fi = _layout_format_item_add(c, n, s, fmt); | ||
3119 | fi->vsize = vsize; | ||
3120 | fi->size = size; | ||
3121 | fi->formatme = 1; | ||
3122 | /* For formats items it's usually | ||
3123 | the same, we don't handle the | ||
3124 | special cases yet. */ | ||
3125 | fi->parent.w = fi->parent.adv = w; | ||
3126 | fi->parent.h = h; | ||
3127 | } | ||
3128 | /* Not sure if it's the best handling, but will do it for now. */ | ||
3129 | fmt = _layout_format_push(c, fmt, n); | ||
3130 | handled = 1; | ||
3131 | } | ||
3132 | |||
3133 | if (!handled) | ||
3134 | { | ||
3135 | Eina_Bool push_fmt = EINA_FALSE; | ||
3136 | if (s[0] == '+') | ||
3137 | { | ||
3138 | fmt = _layout_format_push(c, fmt, n); | ||
3139 | s++; | ||
3140 | push_fmt = EINA_TRUE; | ||
3141 | } | ||
3142 | else if (s[0] == '-') | ||
3143 | { | ||
3144 | fmt = _layout_format_pop(c, n->orig_format); | ||
3145 | s++; | ||
3146 | } | ||
3147 | while ((item = _format_parse(&s))) | ||
3148 | { | ||
3149 | if (_format_is_param(item)) | ||
3150 | { | ||
3151 | /* Only handle it if it's a push format, otherwise, | ||
3152 | * don't let overwrite the format stack.. */ | ||
3153 | if (push_fmt) | ||
3154 | { | ||
3155 | _layout_format_value_handle(c, fmt, item); | ||
3156 | } | ||
3157 | } | ||
3158 | else if (create_item) | ||
3159 | { | ||
3160 | if ((_IS_PARAGRAPH_SEPARATOR(c->o, item)) || | ||
3161 | (_IS_LINE_SEPARATOR(item))) | ||
3162 | { | ||
3163 | Evas_Object_Textblock_Format_Item *fi; | ||
3164 | |||
3165 | fi = _layout_format_item_add(c, n, item, fmt); | ||
3166 | |||
3167 | fi->parent.w = fi->parent.adv = 0; | ||
3168 | } | ||
3169 | else if ((!strcmp(item, "\t")) || (!strcmp(item, "\\t"))) | ||
3170 | { | ||
3171 | Evas_Object_Textblock_Format_Item *fi; | ||
3172 | |||
3173 | fi = _layout_format_item_add(c, n, item, fmt); | ||
3174 | fi->parent.w = fi->parent.adv = fmt->tabstops; | ||
3175 | fi->formatme = 1; | ||
3176 | } | ||
3177 | } | ||
3178 | } | ||
3179 | _format_finalize(c->obj, fmt); | ||
3180 | } | ||
3181 | |||
3182 | { | ||
3183 | Evas_Coord pad_l, pad_r, pad_t, pad_b; | ||
3184 | pad_l = pad_r = pad_t = pad_b = 0; | ||
3185 | evas_text_style_pad_get(fmt->style, &pad_l, &pad_r, &pad_t, &pad_b); | ||
3186 | if (pad_l > *style_pad_l) *style_pad_l = pad_l; | ||
3187 | if (pad_r > *style_pad_r) *style_pad_r = pad_r; | ||
3188 | if (pad_t > *style_pad_t) *style_pad_t = pad_t; | ||
3189 | if (pad_b > *style_pad_b) *style_pad_b = pad_b; | ||
3190 | } | ||
3191 | |||
3192 | if (fmt->underline2) | ||
3193 | c->have_underline2 = 1; | ||
3194 | else if (fmt->underline || fmt->underline_dash) | ||
3195 | c->have_underline = 1; | ||
3196 | *_fmt = fmt; | ||
3197 | } | ||
3198 | |||
3199 | static void | ||
3200 | _layout_update_par(Ctxt *c) | ||
3201 | { | ||
3202 | Evas_Object_Textblock_Paragraph *last_par; | ||
3203 | last_par = (Evas_Object_Textblock_Paragraph *) | ||
3204 | EINA_INLIST_GET(c->par)->prev; | ||
3205 | if (last_par) | ||
3206 | { | ||
3207 | c->par->y = last_par->y + last_par->h; | ||
3208 | } | ||
3209 | else | ||
3210 | { | ||
3211 | c->par->y = 0; | ||
3212 | } | ||
3213 | } | ||
3214 | |||
3215 | /* -1 means no wrap */ | ||
3216 | static int | ||
3217 | _layout_get_charwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, | ||
3218 | const Evas_Object_Textblock_Text_Item *ti, size_t line_start, | ||
3219 | const char *breaks) | ||
3220 | { | ||
3221 | int wrap; | ||
3222 | size_t uwrap; | ||
3223 | size_t len = eina_ustrbuf_length_get(ti->parent.text_node->unicode); | ||
3224 | /* Currently not being used, because it doesn't contain relevant | ||
3225 | * information */ | ||
3226 | (void) breaks; | ||
3227 | |||
3228 | { | ||
3229 | wrap = _layout_text_cutoff_get(c, fmt, ti); | ||
3230 | if (wrap < 0) | ||
3231 | return -1; | ||
3232 | uwrap = (size_t) wrap + ti->parent.text_pos; | ||
3233 | } | ||
3234 | |||
3235 | |||
3236 | if (uwrap == line_start) | ||
3237 | { | ||
3238 | uwrap = ti->parent.text_pos + | ||
3239 | (size_t) evas_common_text_props_cluster_next(&ti->text_props, wrap); | ||
3240 | } | ||
3241 | if ((uwrap <= line_start) || (uwrap > len)) | ||
3242 | return -1; | ||
3243 | |||
3244 | return uwrap; | ||
3245 | } | ||
3246 | |||
3247 | /* -1 means no wrap */ | ||
3248 | #ifdef HAVE_LINEBREAK | ||
3249 | |||
3250 | /* Allow break means: if we can break after the current char */ | ||
3251 | #define ALLOW_BREAK(i) \ | ||
3252 | (breaks[i] <= LINEBREAK_ALLOWBREAK) | ||
3253 | |||
3254 | #else | ||
3255 | |||
3256 | #define ALLOW_BREAK(i) \ | ||
3257 | (_is_white(str[i])) | ||
3258 | |||
3259 | #endif | ||
3260 | static int | ||
3261 | _layout_get_word_mixwrap_common(Ctxt *c, Evas_Object_Textblock_Format *fmt, | ||
3262 | const Evas_Object_Textblock_Text_Item *ti, Eina_Bool mixed_wrap, | ||
3263 | size_t line_start, const char *breaks) | ||
3264 | { | ||
3265 | Eina_Bool wrap_after = EINA_FALSE; | ||
3266 | size_t wrap; | ||
3267 | size_t orig_wrap; | ||
3268 | const Eina_Unicode *str = eina_ustrbuf_string_get( | ||
3269 | ti->parent.text_node->unicode); | ||
3270 | int item_start = ti->parent.text_pos; | ||
3271 | size_t len = eina_ustrbuf_length_get(ti->parent.text_node->unicode); | ||
3272 | #ifndef HAVE_LINEBREAK | ||
3273 | /* Not used without liblinebreak ATM. */ | ||
3274 | (void) breaks; | ||
3275 | #endif | ||
3276 | |||
3277 | { | ||
3278 | int swrap = -1; | ||
3279 | swrap = _layout_text_cutoff_get(c, fmt, ti); | ||
3280 | /* Avoiding too small textblocks to even contain one char. | ||
3281 | * FIXME: This can cause breaking inside ligatures. */ | ||
3282 | |||
3283 | if (swrap < 0) | ||
3284 | return -1; | ||
3285 | |||
3286 | orig_wrap = wrap = swrap + item_start; | ||
3287 | } | ||
3288 | |||
3289 | if (wrap > line_start) | ||
3290 | { | ||
3291 | /* The wrapping point found is the first char of the next string | ||
3292 | the rest works on the last char of the previous string. | ||
3293 | If it's a whitespace, then it's ok, and no need to go back | ||
3294 | because we'll remove it anyway. */ | ||
3295 | if (!_is_white(str[wrap])) | ||
3296 | MOVE_PREV_UNTIL(line_start, wrap); | ||
3297 | /* If there's a breakable point inside the text, scan backwards until | ||
3298 | * we find it */ | ||
3299 | while (wrap > line_start) | ||
3300 | { | ||
3301 | if (ALLOW_BREAK(wrap)) | ||
3302 | break; | ||
3303 | wrap--; | ||
3304 | } | ||
3305 | |||
3306 | if ((wrap > line_start) || | ||
3307 | ((wrap == line_start) && (ALLOW_BREAK(wrap)) && (wrap < len))) | ||
3308 | { | ||
3309 | /* We found a suitable wrapping point, break here. */ | ||
3310 | MOVE_NEXT_UNTIL(len, wrap); | ||
3311 | return wrap; | ||
3312 | } | ||
3313 | else | ||
3314 | { | ||
3315 | if (mixed_wrap) | ||
3316 | { | ||
3317 | return ((orig_wrap >= line_start) && (orig_wrap < len)) ? | ||
3318 | ((int) orig_wrap) : -1; | ||
3319 | } | ||
3320 | else | ||
3321 | { | ||
3322 | /* Scan forward to find the next wrapping point */ | ||
3323 | wrap = orig_wrap; | ||
3324 | wrap_after = EINA_TRUE; | ||
3325 | } | ||
3326 | } | ||
3327 | } | ||
3328 | |||
3329 | /* If we need to find the position after the cutting point */ | ||
3330 | if ((wrap == line_start) || (wrap_after)) | ||
3331 | { | ||
3332 | if (mixed_wrap) | ||
3333 | { | ||
3334 | return _layout_get_charwrap(c, fmt, ti, | ||
3335 | line_start, breaks); | ||
3336 | } | ||
3337 | else | ||
3338 | { | ||
3339 | while (wrap < len) | ||
3340 | { | ||
3341 | if (ALLOW_BREAK(wrap)) | ||
3342 | break; | ||
3343 | wrap++; | ||
3344 | } | ||
3345 | |||
3346 | |||
3347 | if ((wrap < len) && (wrap > line_start)) | ||
3348 | { | ||
3349 | MOVE_NEXT_UNTIL(len, wrap); | ||
3350 | return wrap; | ||
3351 | } | ||
3352 | else | ||
3353 | { | ||
3354 | return -1; | ||
3355 | } | ||
3356 | } | ||
3357 | } | ||
3358 | |||
3359 | return -1; | ||
3360 | } | ||
3361 | |||
3362 | /* -1 means no wrap */ | ||
3363 | static int | ||
3364 | _layout_get_wordwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, | ||
3365 | const Evas_Object_Textblock_Text_Item *ti, size_t line_start, | ||
3366 | const char *breaks) | ||
3367 | { | ||
3368 | return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_FALSE, line_start, | ||
3369 | breaks); | ||
3370 | } | ||
3371 | |||
3372 | /* -1 means no wrap */ | ||
3373 | static int | ||
3374 | _layout_get_mixedwrap(Ctxt *c, Evas_Object_Textblock_Format *fmt, | ||
3375 | const Evas_Object_Textblock_Text_Item *ti, size_t line_start, | ||
3376 | const char *breaks) | ||
3377 | { | ||
3378 | return _layout_get_word_mixwrap_common(c, fmt, ti, EINA_TRUE, line_start, | ||
3379 | breaks); | ||
3380 | } | ||
3381 | |||
3382 | /* Should be moved inside _layout_ellipsis_item_new once we fix the hack in | ||
3383 | * textblock render */ | ||
3384 | static const Eina_Unicode _ellip_str[2] = { 0x2026, '\0' }; | ||
3385 | |||
3386 | static Evas_Object_Textblock_Text_Item * | ||
3387 | _layout_ellipsis_item_new(Ctxt *c, const Evas_Object_Textblock_Item *cur_it) | ||
3388 | { | ||
3389 | Evas_Object_Textblock_Text_Item *ellip_ti; | ||
3390 | Evas_Script_Type script; | ||
3391 | Evas_Font_Instance *script_fi = NULL, *cur_fi; | ||
3392 | size_t len = 1; /* The length of _ellip_str */ | ||
3393 | |||
3394 | /* We can free it here, cause there's only one ellipsis item per tb. */ | ||
3395 | if (c->o->ellip_ti) _item_free(c->obj, NULL, _ITEM(c->o->ellip_ti)); | ||
3396 | c->o->ellip_ti = ellip_ti = _layout_text_item_new(c, | ||
3397 | eina_list_data_get(eina_list_last(c->format_stack))); | ||
3398 | ellip_ti->parent.text_node = cur_it->text_node; | ||
3399 | ellip_ti->parent.text_pos = cur_it->text_pos; | ||
3400 | script = evas_common_language_script_type_get(_ellip_str, len); | ||
3401 | |||
3402 | evas_common_text_props_bidi_set(&ellip_ti->text_props, | ||
3403 | c->par->bidi_props, ellip_ti->parent.text_pos); | ||
3404 | evas_common_text_props_script_set (&ellip_ti->text_props, script); | ||
3405 | |||
3406 | if (ellip_ti->parent.format->font.font) | ||
3407 | { | ||
3408 | /* It's only 1 char anyway, we don't need the run end. */ | ||
3409 | (void) c->ENFN->font_run_end_get(c->ENDT, | ||
3410 | ellip_ti->parent.format->font.font, &script_fi, &cur_fi, | ||
3411 | script, _ellip_str, len); | ||
3412 | |||
3413 | c->ENFN->font_text_props_info_create(c->ENDT, | ||
3414 | cur_fi, _ellip_str, &ellip_ti->text_props, | ||
3415 | c->par->bidi_props, ellip_ti->parent.text_pos, len); | ||
3416 | } | ||
3417 | |||
3418 | _text_item_update_sizes(c, ellip_ti); | ||
3419 | |||
3420 | if (cur_it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
3421 | { | ||
3422 | ellip_ti->parent.text_pos += _ITEM_TEXT(cur_it)->text_props.text_len | ||
3423 | - 1; | ||
3424 | } | ||
3425 | else | ||
3426 | { | ||
3427 | ellip_ti->parent.text_pos++; | ||
3428 | } | ||
3429 | |||
3430 | return ellip_ti; | ||
3431 | } | ||
3432 | |||
3433 | /** | ||
3434 | * @internel | ||
3435 | * Handle ellipsis | ||
3436 | */ | ||
3437 | static inline void | ||
3438 | _layout_handle_ellipsis(Ctxt *c, Evas_Object_Textblock_Item *it, Eina_List *i) | ||
3439 | { | ||
3440 | Evas_Object_Textblock_Text_Item *ellip_ti; | ||
3441 | Evas_Object_Textblock_Item *last_it; | ||
3442 | Evas_Coord save_cx; | ||
3443 | int wrap; | ||
3444 | ellip_ti = _layout_ellipsis_item_new(c, it); | ||
3445 | last_it = it; | ||
3446 | |||
3447 | save_cx = c->x; | ||
3448 | c->w -= ellip_ti->parent.w; | ||
3449 | |||
3450 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
3451 | { | ||
3452 | Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it); | ||
3453 | |||
3454 | wrap = _layout_text_cutoff_get(c, last_it->format, ti); | ||
3455 | if ((wrap > 0) && !IS_AT_END(ti, (size_t) wrap)) | ||
3456 | { | ||
3457 | _layout_item_text_split_strip_white(c, ti, i, wrap); | ||
3458 | } | ||
3459 | else if ((wrap == 0) && (c->ln->items)) | ||
3460 | { | ||
3461 | last_it = _ITEM(EINA_INLIST_GET(c->ln->items)->last); | ||
3462 | } | ||
3463 | } | ||
3464 | else if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) | ||
3465 | { | ||
3466 | /* We don't want to add this format item. */ | ||
3467 | last_it = NULL; | ||
3468 | } | ||
3469 | |||
3470 | c->x = save_cx; | ||
3471 | c->w += ellip_ti->parent.w; | ||
3472 | /* If we should add this item, do it */ | ||
3473 | if (last_it == it) | ||
3474 | { | ||
3475 | c->ln->items = (Evas_Object_Textblock_Item *) | ||
3476 | eina_inlist_append(EINA_INLIST_GET(c->ln->items), | ||
3477 | EINA_INLIST_GET(it)); | ||
3478 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) | ||
3479 | { | ||
3480 | Evas_Object_Textblock_Format_Item *fi; | ||
3481 | fi = _ITEM_FORMAT(it); | ||
3482 | fi->y = c->y; | ||
3483 | } | ||
3484 | } | ||
3485 | c->ln->items = (Evas_Object_Textblock_Item *) | ||
3486 | eina_inlist_append(EINA_INLIST_GET(c->ln->items), | ||
3487 | EINA_INLIST_GET(_ITEM(ellip_ti))); | ||
3488 | _layout_line_finalize(c, ellip_ti->parent.format); | ||
3489 | } | ||
3490 | |||
3491 | #ifdef BIDI_SUPPORT | ||
3492 | static void | ||
3493 | _layout_paragraph_reorder_lines(Evas_Object_Textblock_Paragraph *par) | ||
3494 | { | ||
3495 | Evas_Object_Textblock_Line *ln; | ||
3496 | |||
3497 | EINA_INLIST_FOREACH(EINA_INLIST_GET(par->lines), ln) | ||
3498 | { | ||
3499 | _layout_line_reorder(ln); | ||
3500 | } | ||
3501 | } | ||
3502 | #endif | ||
3503 | |||
3504 | static void | ||
3505 | _layout_paragraph_render(Evas_Object_Textblock *o, | ||
3506 | Evas_Object_Textblock_Paragraph *par) | ||
3507 | { | ||
3508 | if (par->rendered) | ||
3509 | return; | ||
3510 | par->rendered = EINA_TRUE; | ||
3511 | |||
3512 | #ifdef BIDI_SUPPORT | ||
3513 | if (par->is_bidi) | ||
3514 | { | ||
3515 | _layout_update_bidi_props(o, par); | ||
3516 | _layout_paragraph_reorder_lines(par); | ||
3517 | /* Clear the bidi props because we don't need them anymore. */ | ||
3518 | if (par->bidi_props) | ||
3519 | { | ||
3520 | evas_bidi_paragraph_props_unref(par->bidi_props); | ||
3521 | par->bidi_props = NULL; | ||
3522 | } | ||
3523 | } | ||
3524 | #endif | ||
3525 | } | ||
3526 | |||
3527 | /* 0 means go ahead, 1 means break without an error, 2 means | ||
3528 | * break with an error, should probably clean this a bit (enum/macro) | ||
3529 | * FIXME ^ */ | ||
3530 | static int | ||
3531 | _layout_par(Ctxt *c) | ||
3532 | { | ||
3533 | Evas_Object_Textblock_Item *it; | ||
3534 | Eina_List *i; | ||
3535 | int ret = 0; | ||
3536 | int wrap = -1; | ||
3537 | char *line_breaks = NULL; | ||
3538 | |||
3539 | if (!c->par->logical_items) | ||
3540 | return 2; | ||
3541 | |||
3542 | /* We want to show it. */ | ||
3543 | c->par->visible = 1; | ||
3544 | |||
3545 | /* Check if we need to skip this paragraph because it's already layouted | ||
3546 | * correctly, and mark handled nodes as dirty. */ | ||
3547 | c->par->line_no = c->line_no; | ||
3548 | |||
3549 | if (c->par->text_node) | ||
3550 | { | ||
3551 | /* Skip this paragraph if width is the same, there is no ellipsis | ||
3552 | * and we aren't just calculating. */ | ||
3553 | if (!c->par->text_node->is_new && !c->par->text_node->dirty && | ||
3554 | !c->width_changed && c->par->lines && | ||
3555 | !c->o->have_ellipsis) | ||
3556 | { | ||
3557 | Evas_Object_Textblock_Line *ln; | ||
3558 | /* Update c->line_no */ | ||
3559 | ln = (Evas_Object_Textblock_Line *) | ||
3560 | EINA_INLIST_GET(c->par->lines)->last; | ||
3561 | if (ln) | ||
3562 | c->line_no = c->par->line_no + ln->line_no + 1; | ||
3563 | return 0; | ||
3564 | } | ||
3565 | c->par->text_node->dirty = EINA_FALSE; | ||
3566 | c->par->text_node->is_new = EINA_FALSE; | ||
3567 | c->par->rendered = EINA_FALSE; | ||
3568 | |||
3569 | /* Merge back and clear the paragraph */ | ||
3570 | { | ||
3571 | Eina_List *itr, *itr_next; | ||
3572 | Evas_Object_Textblock_Item *ititr, *prev_it = NULL; | ||
3573 | _paragraph_clear(c->obj, c->par); | ||
3574 | EINA_LIST_FOREACH_SAFE(c->par->logical_items, itr, itr_next, ititr) | ||
3575 | { | ||
3576 | if (ititr->merge && prev_it && | ||
3577 | (prev_it->type == EVAS_TEXTBLOCK_ITEM_TEXT) && | ||
3578 | (ititr->type == EVAS_TEXTBLOCK_ITEM_TEXT)) | ||
3579 | { | ||
3580 | _layout_item_merge_and_free(c, _ITEM_TEXT(prev_it), | ||
3581 | _ITEM_TEXT(ititr)); | ||
3582 | c->par->logical_items = | ||
3583 | eina_list_remove_list(c->par->logical_items, itr); | ||
3584 | } | ||
3585 | else | ||
3586 | { | ||
3587 | prev_it = ititr; | ||
3588 | } | ||
3589 | } | ||
3590 | } | ||
3591 | } | ||
3592 | |||
3593 | c->y = c->par->y; | ||
3594 | |||
3595 | it = _ITEM(eina_list_data_get(c->par->logical_items)); | ||
3596 | _layout_line_new(c, it->format); | ||
3597 | /* We walk on our own because we want to be able to add items from | ||
3598 | * inside the list and then walk them on the next iteration. */ | ||
3599 | for (i = c->par->logical_items ; i ; ) | ||
3600 | { | ||
3601 | int adv_line = 0; | ||
3602 | int redo_item = 0; | ||
3603 | it = _ITEM(eina_list_data_get(i)); | ||
3604 | /* Skip visually deleted items */ | ||
3605 | if (it->visually_deleted) | ||
3606 | { | ||
3607 | i = eina_list_next(i); | ||
3608 | continue; | ||
3609 | } | ||
3610 | |||
3611 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
3612 | { | ||
3613 | Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it); | ||
3614 | _layout_format_ascent_descent_adjust(c->obj, &c->maxascent, | ||
3615 | &c->maxdescent, ti->parent.format); | ||
3616 | } | ||
3617 | else | ||
3618 | { | ||
3619 | Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it); | ||
3620 | if (fi->formatme) | ||
3621 | { | ||
3622 | /* If there are no text items yet, calc ascent/descent | ||
3623 | * according to the current format. */ | ||
3624 | if (c->maxascent + c->maxdescent == 0) | ||
3625 | _layout_format_ascent_descent_adjust(c->obj, &c->maxascent, | ||
3626 | &c->maxdescent, it->format); | ||
3627 | |||
3628 | _layout_calculate_format_item_size(c->obj, fi, &c->maxascent, | ||
3629 | &c->maxdescent, &fi->y, &fi->parent.w, &fi->parent.h); | ||
3630 | fi->parent.adv = fi->parent.w; | ||
3631 | } | ||
3632 | } | ||
3633 | |||
3634 | |||
3635 | /* Check if we need to wrap, i.e the text is bigger than the width, | ||
3636 | or we already found a wrap point. */ | ||
3637 | if ((c->w >= 0) && | ||
3638 | (((c->x + it->adv) > | ||
3639 | (c->w - c->o->style_pad.l - c->o->style_pad.r - | ||
3640 | c->marginl - c->marginr)) || (wrap > 0))) | ||
3641 | { | ||
3642 | /* Handle ellipsis here. If we don't have more width left | ||
3643 | * and no height left, or no more width left and no wrapping. */ | ||
3644 | if ((it->format->ellipsis == 1.0) && (c->h >= 0) && | ||
3645 | ((2 * it->h + c->y > | ||
3646 | c->h - c->o->style_pad.t - c->o->style_pad.b) || | ||
3647 | (!it->format->wrap_word && !it->format->wrap_char && | ||
3648 | !it->format->wrap_mixed))) | ||
3649 | { | ||
3650 | _layout_handle_ellipsis(c, it, i); | ||
3651 | ret = 1; | ||
3652 | goto end; | ||
3653 | } | ||
3654 | /* If we want to wrap and it's worth checking for wrapping | ||
3655 | * (i.e there's actually text). */ | ||
3656 | else if ((it->format->wrap_word || it->format->wrap_char || | ||
3657 | it->format->wrap_mixed) && it->text_node) | ||
3658 | { | ||
3659 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) | ||
3660 | { | ||
3661 | /* Don't wrap if it's the only item */ | ||
3662 | if (c->ln->items) | ||
3663 | { | ||
3664 | /*FIXME: I should handle format correctly, | ||
3665 | i.e verify we are allowed to break here */ | ||
3666 | _layout_line_advance(c, it->format); | ||
3667 | wrap = -1; | ||
3668 | } | ||
3669 | } | ||
3670 | else | ||
3671 | { | ||
3672 | Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it); | ||
3673 | size_t line_start; | ||
3674 | |||
3675 | #ifdef HAVE_LINEBREAK | ||
3676 | /* If we haven't calculated the linebreaks yet, | ||
3677 | * do */ | ||
3678 | if (!line_breaks) | ||
3679 | { | ||
3680 | /* Only relevant in those cases */ | ||
3681 | if (it->format->wrap_word || it->format->wrap_mixed) | ||
3682 | { | ||
3683 | const char *lang; | ||
3684 | lang = (it->format->font.fdesc) ? | ||
3685 | it->format->font.fdesc->lang : ""; | ||
3686 | size_t len = | ||
3687 | eina_ustrbuf_length_get( | ||
3688 | it->text_node->unicode); | ||
3689 | line_breaks = malloc(len); | ||
3690 | set_linebreaks_utf32((const utf32_t *) | ||
3691 | eina_ustrbuf_string_get( | ||
3692 | it->text_node->unicode), | ||
3693 | len, lang, line_breaks); | ||
3694 | } | ||
3695 | } | ||
3696 | #endif | ||
3697 | if (c->ln->items) | ||
3698 | line_start = c->ln->items->text_pos; | ||
3699 | else | ||
3700 | line_start = ti->parent.text_pos; | ||
3701 | |||
3702 | adv_line = 1; | ||
3703 | /* If we don't already have a wrap point from before */ | ||
3704 | if (wrap < 0) | ||
3705 | { | ||
3706 | if (it->format->wrap_word) | ||
3707 | wrap = _layout_get_wordwrap(c, it->format, ti, | ||
3708 | line_start, line_breaks); | ||
3709 | else if (it->format->wrap_char) | ||
3710 | wrap = _layout_get_charwrap(c, it->format, ti, | ||
3711 | line_start, line_breaks); | ||
3712 | else if (it->format->wrap_mixed) | ||
3713 | wrap = _layout_get_mixedwrap(c, it->format, ti, | ||
3714 | line_start, line_breaks); | ||
3715 | else | ||
3716 | wrap = -1; | ||
3717 | } | ||
3718 | |||
3719 | /* If it's before the item, rollback and apply. | ||
3720 | if it's in the item, cut. | ||
3721 | If it's after the item, delay the cut */ | ||
3722 | if (wrap > 0) | ||
3723 | { | ||
3724 | size_t uwrap = (size_t) wrap; | ||
3725 | if (uwrap < ti->parent.text_pos) | ||
3726 | { | ||
3727 | /* Rollback latest additions, and cut that | ||
3728 | item */ | ||
3729 | i = eina_list_prev(i); | ||
3730 | it = eina_list_data_get(i); | ||
3731 | while (uwrap < it->text_pos) | ||
3732 | { | ||
3733 | c->ln->items = _ITEM( | ||
3734 | eina_inlist_remove( | ||
3735 | EINA_INLIST_GET(c->ln->items), | ||
3736 | EINA_INLIST_GET(it))); | ||
3737 | i = eina_list_prev(i); | ||
3738 | it = eina_list_data_get(i); | ||
3739 | } | ||
3740 | c->x = it->x; | ||
3741 | c->ln->items = _ITEM( | ||
3742 | eina_inlist_remove( | ||
3743 | EINA_INLIST_GET(c->ln->items), | ||
3744 | EINA_INLIST_GET(it))); | ||
3745 | continue; | ||
3746 | } | ||
3747 | /* If it points to the end, it means the previous | ||
3748 | * char is a whitespace we should remove, so this | ||
3749 | * is a wanted cutting point. */ | ||
3750 | else if (uwrap > ti->parent.text_pos + | ||
3751 | ti->text_props.text_len) | ||
3752 | wrap = -1; /* Delay the cut in a smart way | ||
3753 | i.e use the item_pos as the line_start, because | ||
3754 | there's already no cut before*/ | ||
3755 | else | ||
3756 | wrap -= ti->parent.text_pos; /* Cut here */ | ||
3757 | } | ||
3758 | |||
3759 | if (wrap > 0) | ||
3760 | { | ||
3761 | _layout_item_text_split_strip_white(c, ti, i, wrap); | ||
3762 | } | ||
3763 | else if (wrap == 0) | ||
3764 | { | ||
3765 | /* Should wrap before the item */ | ||
3766 | adv_line = 0; | ||
3767 | redo_item = 1; | ||
3768 | _layout_line_advance(c, it->format); | ||
3769 | } | ||
3770 | /* Reset wrap */ | ||
3771 | wrap = -1; | ||
3772 | } | ||
3773 | } | ||
3774 | } | ||
3775 | |||
3776 | if (!redo_item && !it->visually_deleted) | ||
3777 | { | ||
3778 | c->ln->items = (Evas_Object_Textblock_Item *) | ||
3779 | eina_inlist_append(EINA_INLIST_GET(c->ln->items), | ||
3780 | EINA_INLIST_GET(it)); | ||
3781 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) | ||
3782 | { | ||
3783 | Evas_Object_Textblock_Format_Item *fi; | ||
3784 | fi = _ITEM_FORMAT(it); | ||
3785 | fi->y = c->y; | ||
3786 | /* If it's a newline, and we are not in newline compat | ||
3787 | * mode, or we are in newline compat mode, and this is | ||
3788 | * not used as a paragraph separator, advance */ | ||
3789 | if (fi->item && _IS_LINE_SEPARATOR(fi->item) && | ||
3790 | (!c->o->legacy_newline || | ||
3791 | eina_list_next(i))) | ||
3792 | { | ||
3793 | adv_line = 1; | ||
3794 | } | ||
3795 | } | ||
3796 | c->x += it->adv; | ||
3797 | i = eina_list_next(i); | ||
3798 | } | ||
3799 | if (adv_line) | ||
3800 | { | ||
3801 | /* Each line is according to the first item in it, and here | ||
3802 | * i is already the next item (or the current if we redo it) */ | ||
3803 | if (i) | ||
3804 | { | ||
3805 | it = _ITEM(eina_list_data_get(i)); | ||
3806 | } | ||
3807 | _layout_line_advance(c, it->format); | ||
3808 | } | ||
3809 | } | ||
3810 | if (c->ln->items) | ||
3811 | { | ||
3812 | /* Here 'it' is the last format used */ | ||
3813 | _layout_line_finalize(c, it->format); | ||
3814 | } | ||
3815 | |||
3816 | end: | ||
3817 | #ifdef HAVE_LINEBREAK | ||
3818 | if (line_breaks) | ||
3819 | free(line_breaks); | ||
3820 | #endif | ||
3821 | |||
3822 | return ret; | ||
3823 | } | ||
3824 | |||
3825 | /** | ||
3826 | * @internal | ||
3827 | * Invalidate text nodes according to format changes | ||
3828 | * This goes through all the new format changes and marks the text nodes | ||
3829 | * that should be invalidated because of format changes. | ||
3830 | * | ||
3831 | * @param c the working context. | ||
3832 | */ | ||
3833 | static inline void | ||
3834 | _format_changes_invalidate_text_nodes(Ctxt *c) | ||
3835 | { | ||
3836 | Evas_Object_Textblock_Node_Format *fnode = c->o->format_nodes; | ||
3837 | Evas_Object_Textblock_Node_Text *start_n = NULL; | ||
3838 | Eina_List *fstack = NULL; | ||
3839 | int balance = 0; | ||
3840 | while (fnode) | ||
3841 | { | ||
3842 | if (fnode->is_new) | ||
3843 | { | ||
3844 | const char *fstr = fnode->orig_format; | ||
3845 | /* balance < 0 means we gave up and everything should be | ||
3846 | * invalidated */ | ||
3847 | if (*fstr == '+') | ||
3848 | { | ||
3849 | balance++; | ||
3850 | if (!fstack) | ||
3851 | start_n = fnode->text_node; | ||
3852 | fstack = eina_list_prepend(fstack, fnode); | ||
3853 | } | ||
3854 | else if (*fstr == '-') | ||
3855 | { | ||
3856 | size_t fstr_len; | ||
3857 | /* Skip the '-' */ | ||
3858 | fstr++; | ||
3859 | fstr_len = strlen(fstr); | ||
3860 | /* Generic popper, just pop */ | ||
3861 | if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0]) | ||
3862 | { | ||
3863 | fstack = eina_list_remove_list(fstack, fstack); | ||
3864 | balance--; | ||
3865 | } | ||
3866 | /* Find the matching format and pop it, if the matching format | ||
3867 | * is out format, i.e the last one, pop and break. */ | ||
3868 | else | ||
3869 | { | ||
3870 | Eina_List *i; | ||
3871 | Evas_Object_Textblock_Node_Format *fnode2; | ||
3872 | EINA_LIST_FOREACH(fstack, i, fnode2) | ||
3873 | { | ||
3874 | if (_FORMAT_IS_CLOSER_OF( | ||
3875 | fnode2->orig_format, fstr, fstr_len)) | ||
3876 | { | ||
3877 | fstack = eina_list_remove_list(fstack, i); | ||
3878 | break; | ||
3879 | } | ||
3880 | } | ||
3881 | balance--; | ||
3882 | } | ||
3883 | |||
3884 | if (!fstack) | ||
3885 | { | ||
3886 | Evas_Object_Textblock_Node_Text *f_tnode = | ||
3887 | fnode->text_node; | ||
3888 | while (start_n) | ||
3889 | { | ||
3890 | start_n->dirty = EINA_TRUE; | ||
3891 | if (start_n == f_tnode) | ||
3892 | break; | ||
3893 | start_n = | ||
3894 | _NODE_TEXT(EINA_INLIST_GET(start_n)->next); | ||
3895 | } | ||
3896 | start_n = NULL; | ||
3897 | } | ||
3898 | } | ||
3899 | else if (!fnode->visible) | ||
3900 | balance = -1; | ||
3901 | |||
3902 | if (balance < 0) | ||
3903 | { | ||
3904 | /* if we don't already have a starting point, use the | ||
3905 | * current paragraph. */ | ||
3906 | if (!start_n) | ||
3907 | start_n = fnode->text_node; | ||
3908 | break; | ||
3909 | } | ||
3910 | } | ||
3911 | fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
3912 | } | ||
3913 | |||
3914 | if (balance != 0) | ||
3915 | { | ||
3916 | while (start_n) | ||
3917 | { | ||
3918 | start_n->dirty = EINA_TRUE; | ||
3919 | start_n = _NODE_TEXT(EINA_INLIST_GET(start_n)->next); | ||
3920 | } | ||
3921 | } | ||
3922 | } | ||
3923 | |||
3924 | |||
3925 | /** FIXME: Document */ | ||
3926 | static void | ||
3927 | _layout_pre(Ctxt *c, int *style_pad_l, int *style_pad_r, int *style_pad_t, | ||
3928 | int *style_pad_b) | ||
3929 | { | ||
3930 | Evas_Object *obj = c->obj; | ||
3931 | Evas_Object_Textblock *o = c->o; | ||
3932 | /* Mark text nodes as dirty if format have changed. */ | ||
3933 | if (c->o->format_changed) | ||
3934 | { | ||
3935 | _format_changes_invalidate_text_nodes(c); | ||
3936 | } | ||
3937 | |||
3938 | if (o->content_changed) | ||
3939 | { | ||
3940 | Evas_Object_Textblock_Node_Text *n; | ||
3941 | c->o->have_ellipsis = 0; | ||
3942 | c->par = c->paragraphs = o->paragraphs; | ||
3943 | /* Go through all the text nodes to create the logical layout */ | ||
3944 | EINA_INLIST_FOREACH(c->o->text_nodes, n) | ||
3945 | { | ||
3946 | Evas_Object_Textblock_Node_Format *fnode; | ||
3947 | size_t start; | ||
3948 | int off; | ||
3949 | |||
3950 | /* If it's not a new paragraph, either update it or skip it. | ||
3951 | * Remove all the paragraphs that were deleted */ | ||
3952 | if (!n->is_new) | ||
3953 | { | ||
3954 | /* Remove all the deleted paragraphs at this point */ | ||
3955 | while (c->par->text_node != n) | ||
3956 | { | ||
3957 | Evas_Object_Textblock_Paragraph *tmp_par = | ||
3958 | (Evas_Object_Textblock_Paragraph *) | ||
3959 | EINA_INLIST_GET(c->par)->next; | ||
3960 | |||
3961 | c->paragraphs = (Evas_Object_Textblock_Paragraph *) | ||
3962 | eina_inlist_remove(EINA_INLIST_GET(c->paragraphs), | ||
3963 | EINA_INLIST_GET(c->par)); | ||
3964 | _paragraph_free(obj, c->par); | ||
3965 | |||
3966 | c->par = tmp_par; | ||
3967 | } | ||
3968 | |||
3969 | /* If it's dirty, remove and recreate, if it's clean, | ||
3970 | * skip to the next. */ | ||
3971 | if (n->dirty) | ||
3972 | { | ||
3973 | Evas_Object_Textblock_Paragraph *prev_par = c->par; | ||
3974 | |||
3975 | _layout_paragraph_new(c, n, EINA_TRUE); | ||
3976 | |||
3977 | c->paragraphs = (Evas_Object_Textblock_Paragraph *) | ||
3978 | eina_inlist_remove(EINA_INLIST_GET(c->paragraphs), | ||
3979 | EINA_INLIST_GET(prev_par)); | ||
3980 | _paragraph_free(obj, prev_par); | ||
3981 | } | ||
3982 | else | ||
3983 | { | ||
3984 | c->par = (Evas_Object_Textblock_Paragraph *) | ||
3985 | EINA_INLIST_GET(c->par)->next; | ||
3986 | |||
3987 | /* Update the format stack according to the node's | ||
3988 | * formats */ | ||
3989 | fnode = n->format_node; | ||
3990 | while (fnode && (fnode->text_node == n)) | ||
3991 | { | ||
3992 | /* Only do this if this actually changes format */ | ||
3993 | if (fnode->format_change) | ||
3994 | _layout_do_format(obj, c, &c->fmt, fnode, | ||
3995 | style_pad_l, style_pad_r, | ||
3996 | style_pad_t, style_pad_b, EINA_FALSE); | ||
3997 | fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
3998 | } | ||
3999 | continue; | ||
4000 | } | ||
4001 | } | ||
4002 | else | ||
4003 | { | ||
4004 | /* If it's a new paragraph, just add it. */ | ||
4005 | _layout_paragraph_new(c, n, EINA_FALSE); | ||
4006 | } | ||
4007 | |||
4008 | #ifdef BIDI_SUPPORT | ||
4009 | _layout_update_bidi_props(c->o, c->par); | ||
4010 | #endif | ||
4011 | |||
4012 | /* For each text node to thorugh all of it's format nodes | ||
4013 | * append text from the start to the offset of the next format | ||
4014 | * using the last format got. if needed it also creates format | ||
4015 | * items this is the core algorithm of the layout mechanism. | ||
4016 | * Skip the unicode replacement chars when there are because | ||
4017 | * we don't want to print them. */ | ||
4018 | fnode = n->format_node; | ||
4019 | start = off = 0; | ||
4020 | while (fnode && (fnode->text_node == n)) | ||
4021 | { | ||
4022 | off += fnode->offset; | ||
4023 | /* No need to skip on the first run, or a non-visible one */ | ||
4024 | _layout_text_append(c, c->fmt, n, start, off, o->repch); | ||
4025 | _layout_do_format(obj, c, &c->fmt, fnode, style_pad_l, | ||
4026 | style_pad_r, style_pad_t, style_pad_b, EINA_TRUE); | ||
4027 | if ((c->have_underline2) || (c->have_underline)) | ||
4028 | { | ||
4029 | if (*style_pad_b < c->underline_extend) | ||
4030 | *style_pad_b = c->underline_extend; | ||
4031 | c->have_underline = 0; | ||
4032 | c->have_underline2 = 0; | ||
4033 | c->underline_extend = 0; | ||
4034 | } | ||
4035 | start += off; | ||
4036 | if (fnode->visible) | ||
4037 | { | ||
4038 | off = -1; | ||
4039 | start++; | ||
4040 | } | ||
4041 | else | ||
4042 | { | ||
4043 | off = 0; | ||
4044 | } | ||
4045 | fnode->is_new = EINA_FALSE; | ||
4046 | fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
4047 | } | ||
4048 | _layout_text_append(c, c->fmt, n, start, -1, o->repch); | ||
4049 | #ifdef BIDI_SUPPORT | ||
4050 | /* Clear the bidi props because we don't need them anymore. */ | ||
4051 | if (c->par->bidi_props) | ||
4052 | { | ||
4053 | evas_bidi_paragraph_props_unref(c->par->bidi_props); | ||
4054 | c->par->bidi_props = NULL; | ||
4055 | } | ||
4056 | #endif | ||
4057 | c->par = (Evas_Object_Textblock_Paragraph *) | ||
4058 | EINA_INLIST_GET(c->par)->next; | ||
4059 | } | ||
4060 | |||
4061 | /* Delete the rest of the layout paragraphs */ | ||
4062 | while (c->par) | ||
4063 | { | ||
4064 | Evas_Object_Textblock_Paragraph *tmp_par = | ||
4065 | (Evas_Object_Textblock_Paragraph *) | ||
4066 | EINA_INLIST_GET(c->par)->next; | ||
4067 | |||
4068 | c->paragraphs = (Evas_Object_Textblock_Paragraph *) | ||
4069 | eina_inlist_remove(EINA_INLIST_GET(c->paragraphs), | ||
4070 | EINA_INLIST_GET(c->par)); | ||
4071 | _paragraph_free(obj, c->par); | ||
4072 | |||
4073 | c->par = tmp_par; | ||
4074 | } | ||
4075 | o->paragraphs = c->paragraphs; | ||
4076 | c->par = NULL; | ||
4077 | } | ||
4078 | |||
4079 | } | ||
4080 | |||
4081 | /** | ||
4082 | * @internal | ||
4083 | * Create the layout from the nodes. | ||
4084 | * | ||
4085 | * @param obj the evas object - NOT NULL. | ||
4086 | * @param calc_only true if should only calc sizes false if should also create the layout.. It assumes native size is being calculated, doesn't support formatted size atm. | ||
4087 | * @param w the object's w, -1 means no wrapping (i.e infinite size) | ||
4088 | * @param h the object's h, -1 means inifinte size. | ||
4089 | * @param w_ret the object's calculated w. | ||
4090 | * @param h_ret the object's calculated h. | ||
4091 | */ | ||
4092 | static void | ||
4093 | _layout(const Evas_Object *obj, int w, int h, int *w_ret, int *h_ret) | ||
4094 | { | ||
4095 | Evas_Object_Textblock *o; | ||
4096 | Ctxt ctxt, *c; | ||
4097 | int style_pad_l = 0, style_pad_r = 0, style_pad_t = 0, style_pad_b = 0; | ||
4098 | |||
4099 | /* setup context */ | ||
4100 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
4101 | c = &ctxt; | ||
4102 | c->obj = (Evas_Object *)obj; | ||
4103 | c->o = o; | ||
4104 | c->paragraphs = c->par = NULL; | ||
4105 | c->format_stack = NULL; | ||
4106 | c->fmt = NULL; | ||
4107 | c->x = c->y = 0; | ||
4108 | c->w = w; | ||
4109 | c->h = h; | ||
4110 | c->wmax = c->hmax = 0; | ||
4111 | c->maxascent = c->maxdescent = 0; | ||
4112 | c->marginl = c->marginr = 0; | ||
4113 | c->have_underline = 0; | ||
4114 | c->have_underline2 = 0; | ||
4115 | c->underline_extend = 0; | ||
4116 | c->line_no = 0; | ||
4117 | c->align = 0.0; | ||
4118 | c->align_auto = EINA_TRUE; | ||
4119 | c->ln = NULL; | ||
4120 | c->width_changed = (obj->cur.geometry.w != o->last_w); | ||
4121 | |||
4122 | /* Start of logical layout creation */ | ||
4123 | /* setup default base style */ | ||
4124 | if ((c->o->style) && (c->o->style->default_tag)) | ||
4125 | { | ||
4126 | c->fmt = _layout_format_push(c, NULL, NULL); | ||
4127 | _format_fill(c->obj, c->fmt, c->o->style->default_tag); | ||
4128 | _format_finalize(c->obj, c->fmt); | ||
4129 | } | ||
4130 | if (!c->fmt) | ||
4131 | { | ||
4132 | if (w_ret) *w_ret = 0; | ||
4133 | if (h_ret) *h_ret = 0; | ||
4134 | return; | ||
4135 | } | ||
4136 | |||
4137 | _layout_pre(c, &style_pad_l, &style_pad_r, &style_pad_t, &style_pad_b); | ||
4138 | c->paragraphs = o->paragraphs; | ||
4139 | |||
4140 | /* If there are no paragraphs, create the minimum needed, | ||
4141 | * if the last paragraph has no lines/text, create that as well */ | ||
4142 | if (!c->paragraphs) | ||
4143 | { | ||
4144 | _layout_paragraph_new(c, NULL, EINA_TRUE); | ||
4145 | o->paragraphs = c->paragraphs; | ||
4146 | } | ||
4147 | c->par = (Evas_Object_Textblock_Paragraph *) | ||
4148 | EINA_INLIST_GET(c->paragraphs)->last; | ||
4149 | if (!c->par->logical_items) | ||
4150 | { | ||
4151 | Evas_Object_Textblock_Text_Item *ti; | ||
4152 | ti = _layout_text_item_new(c, c->fmt); | ||
4153 | ti->parent.text_node = c->par->text_node; | ||
4154 | ti->parent.text_pos = 0; | ||
4155 | _layout_text_add_logical_item(c, ti, NULL); | ||
4156 | } | ||
4157 | |||
4158 | /* End of logical layout creation */ | ||
4159 | |||
4160 | /* Start of visual layout creation */ | ||
4161 | { | ||
4162 | Evas_Object_Textblock_Paragraph *last_vis_par = NULL; | ||
4163 | int par_index_step = o->num_paragraphs / TEXTBLOCK_PAR_INDEX_SIZE; | ||
4164 | int par_count = 1; /* Force it to take the first one */ | ||
4165 | int par_index_pos = 0; | ||
4166 | |||
4167 | if (par_index_step == 0) par_index_step = 1; | ||
4168 | |||
4169 | /* Clear all of the index */ | ||
4170 | memset(o->par_index, 0, sizeof(o->par_index)); | ||
4171 | |||
4172 | EINA_INLIST_FOREACH(c->paragraphs, c->par) | ||
4173 | { | ||
4174 | _layout_update_par(c); | ||
4175 | |||
4176 | /* Break if we should stop here. */ | ||
4177 | if (_layout_par(c)) | ||
4178 | { | ||
4179 | last_vis_par = c->par; | ||
4180 | break; | ||
4181 | } | ||
4182 | |||
4183 | if ((par_index_pos < TEXTBLOCK_PAR_INDEX_SIZE) && (--par_count == 0)) | ||
4184 | { | ||
4185 | par_count = par_index_step; | ||
4186 | |||
4187 | o->par_index[par_index_pos++] = c->par; | ||
4188 | } | ||
4189 | } | ||
4190 | |||
4191 | /* Mark all the rest of the paragraphs as invisible */ | ||
4192 | if (c->par) | ||
4193 | { | ||
4194 | c->par = (Evas_Object_Textblock_Paragraph *) | ||
4195 | EINA_INLIST_GET(c->par)->next; | ||
4196 | while (c->par) | ||
4197 | { | ||
4198 | c->par->visible = 0; | ||
4199 | c->par = (Evas_Object_Textblock_Paragraph *) | ||
4200 | EINA_INLIST_GET(c->par)->next; | ||
4201 | } | ||
4202 | } | ||
4203 | |||
4204 | /* Get the last visible paragraph in the layout */ | ||
4205 | if (!last_vis_par && c->paragraphs) | ||
4206 | last_vis_par = (Evas_Object_Textblock_Paragraph *) | ||
4207 | EINA_INLIST_GET(c->paragraphs)->last; | ||
4208 | |||
4209 | if (last_vis_par) | ||
4210 | c->hmax = last_vis_par->y + last_vis_par->h; | ||
4211 | } | ||
4212 | |||
4213 | /* Clean the rest of the format stack */ | ||
4214 | while (c->format_stack) | ||
4215 | { | ||
4216 | c->fmt = c->format_stack->data; | ||
4217 | c->format_stack = eina_list_remove_list(c->format_stack, c->format_stack); | ||
4218 | _format_unref_free(c->obj, c->fmt); | ||
4219 | } | ||
4220 | |||
4221 | if (w_ret) *w_ret = c->wmax; | ||
4222 | if (h_ret) *h_ret = c->hmax; | ||
4223 | |||
4224 | /* Vertically align the textblock */ | ||
4225 | if ((o->valign > 0.0) && (c->h > c->hmax)) | ||
4226 | { | ||
4227 | Evas_Coord adjustment = (c->h - c->hmax) * o->valign; | ||
4228 | Evas_Object_Textblock_Paragraph *par; | ||
4229 | EINA_INLIST_FOREACH(c->paragraphs, par) | ||
4230 | { | ||
4231 | par->y += adjustment; | ||
4232 | } | ||
4233 | } | ||
4234 | |||
4235 | if ((o->style_pad.l != style_pad_l) || (o->style_pad.r != style_pad_r) || | ||
4236 | (o->style_pad.t != style_pad_t) || (o->style_pad.b != style_pad_b)) | ||
4237 | { | ||
4238 | o->style_pad.l = style_pad_l; | ||
4239 | o->style_pad.r = style_pad_r; | ||
4240 | o->style_pad.t = style_pad_t; | ||
4241 | o->style_pad.b = style_pad_b; | ||
4242 | _paragraphs_clear(obj, c->paragraphs); | ||
4243 | _layout(obj, w, h, w_ret, h_ret); | ||
4244 | } | ||
4245 | } | ||
4246 | |||
4247 | /* | ||
4248 | * @internal | ||
4249 | * Relayout the object according to current object size. | ||
4250 | * | ||
4251 | * @param obj the evas object - NOT NULL. | ||
4252 | */ | ||
4253 | static void | ||
4254 | _relayout(const Evas_Object *obj) | ||
4255 | { | ||
4256 | Evas_Object_Textblock *o; | ||
4257 | |||
4258 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
4259 | _layout(obj, obj->cur.geometry.w, obj->cur.geometry.h, | ||
4260 | &o->formatted.w, &o->formatted.h); | ||
4261 | o->formatted.valid = 1; | ||
4262 | o->last_w = obj->cur.geometry.w; | ||
4263 | o->last_h = obj->cur.geometry.h; | ||
4264 | o->changed = 0; | ||
4265 | o->content_changed = 0; | ||
4266 | o->format_changed = EINA_FALSE; | ||
4267 | o->redraw = 1; | ||
4268 | } | ||
4269 | |||
4270 | /** | ||
4271 | * @internal | ||
4272 | * Find the layout item and line that match the text node and position passed. | ||
4273 | * | ||
4274 | * @param obj the evas object - NOT NULL. | ||
4275 | * @param n the text node - Not null. | ||
4276 | * @param pos the position to look for - valid. | ||
4277 | * @param[out] lnr the line found - not null. | ||
4278 | * @param[out] tir the item found - not null. | ||
4279 | * @see _find_layout_format_item_line_match() | ||
4280 | */ | ||
4281 | static void | ||
4282 | _find_layout_item_line_match(Evas_Object *obj, Evas_Object_Textblock_Node_Text *n, int pos, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr) | ||
4283 | { | ||
4284 | Evas_Object_Textblock_Paragraph *found_par; | ||
4285 | Evas_Object_Textblock_Line *ln; | ||
4286 | Evas_Object_Textblock *o; | ||
4287 | |||
4288 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
4289 | if (!o->formatted.valid) _relayout(obj); | ||
4290 | |||
4291 | found_par = n->par; | ||
4292 | if (found_par) | ||
4293 | { | ||
4294 | _layout_paragraph_render(o, found_par); | ||
4295 | EINA_INLIST_FOREACH(found_par->lines, ln) | ||
4296 | { | ||
4297 | Evas_Object_Textblock_Item *it; | ||
4298 | |||
4299 | EINA_INLIST_FOREACH(ln->items, it) | ||
4300 | { | ||
4301 | /* FIXME: p should be size_t, same goes for pos */ | ||
4302 | int p = (int) it->text_pos; | ||
4303 | |||
4304 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
4305 | { | ||
4306 | Evas_Object_Textblock_Text_Item *ti = | ||
4307 | _ITEM_TEXT(it); | ||
4308 | |||
4309 | p += (int) ti->text_props.text_len; | ||
4310 | } | ||
4311 | else | ||
4312 | { | ||
4313 | p++; | ||
4314 | } | ||
4315 | |||
4316 | if (((pos >= (int) it->text_pos) && (pos < p))) | ||
4317 | { | ||
4318 | *lnr = ln; | ||
4319 | *itr = it; | ||
4320 | return; | ||
4321 | } | ||
4322 | else if (p == pos) | ||
4323 | { | ||
4324 | *lnr = ln; | ||
4325 | *itr = it; | ||
4326 | } | ||
4327 | } | ||
4328 | } | ||
4329 | } | ||
4330 | } | ||
4331 | |||
4332 | /** | ||
4333 | * @internal | ||
4334 | * Return the line number 'line'. | ||
4335 | * | ||
4336 | * @param obj the evas object - NOT NULL. | ||
4337 | * @param line the line to find | ||
4338 | * @return the line of line number or NULL if no line found. | ||
4339 | */ | ||
4340 | static Evas_Object_Textblock_Line * | ||
4341 | _find_layout_line_num(const Evas_Object *obj, int line) | ||
4342 | { | ||
4343 | Evas_Object_Textblock_Paragraph *par; | ||
4344 | Evas_Object_Textblock_Line *ln; | ||
4345 | Evas_Object_Textblock *o; | ||
4346 | |||
4347 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
4348 | |||
4349 | par = _layout_find_paragraph_by_line_no(o, line); | ||
4350 | if (par) | ||
4351 | { | ||
4352 | _layout_paragraph_render(o, par); | ||
4353 | EINA_INLIST_FOREACH(par->lines, ln) | ||
4354 | { | ||
4355 | if (par->line_no + ln->line_no == line) return ln; | ||
4356 | } | ||
4357 | } | ||
4358 | return NULL; | ||
4359 | } | ||
4360 | |||
4361 | EAPI Evas_Object * | ||
4362 | evas_object_textblock_add(Evas *e) | ||
4363 | { | ||
4364 | Evas_Object *obj; | ||
4365 | |||
4366 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
4367 | return NULL; | ||
4368 | MAGIC_CHECK_END(); | ||
4369 | obj = evas_object_new(e); | ||
4370 | evas_object_textblock_init(obj); | ||
4371 | evas_object_inject(obj, e); | ||
4372 | return obj; | ||
4373 | } | ||
4374 | |||
4375 | EAPI Evas_Textblock_Style * | ||
4376 | evas_textblock_style_new(void) | ||
4377 | { | ||
4378 | Evas_Textblock_Style *ts; | ||
4379 | |||
4380 | ts = calloc(1, sizeof(Evas_Textblock_Style)); | ||
4381 | return ts; | ||
4382 | } | ||
4383 | |||
4384 | EAPI void | ||
4385 | evas_textblock_style_free(Evas_Textblock_Style *ts) | ||
4386 | { | ||
4387 | if (!ts) return; | ||
4388 | if (ts->objects) | ||
4389 | { | ||
4390 | ts->delete_me = 1; | ||
4391 | return; | ||
4392 | } | ||
4393 | _style_clear(ts); | ||
4394 | free(ts); | ||
4395 | } | ||
4396 | |||
4397 | EAPI void | ||
4398 | evas_textblock_style_set(Evas_Textblock_Style *ts, const char *text) | ||
4399 | { | ||
4400 | Eina_List *l; | ||
4401 | Evas_Object *obj; | ||
4402 | |||
4403 | if (!ts) return; | ||
4404 | /* If the style wasn't really changed, abort. */ | ||
4405 | if ((!ts->style_text && !text) || | ||
4406 | (ts->style_text && text && !strcmp(text, ts->style_text))) | ||
4407 | return; | ||
4408 | |||
4409 | EINA_LIST_FOREACH(ts->objects, l, obj) | ||
4410 | { | ||
4411 | Evas_Object_Textblock *o; | ||
4412 | |||
4413 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
4414 | _evas_textblock_invalidate_all(o); | ||
4415 | _evas_textblock_changed(o, obj); | ||
4416 | } | ||
4417 | |||
4418 | _style_replace(ts, text); | ||
4419 | |||
4420 | if (ts->style_text) | ||
4421 | { | ||
4422 | // format MUST be KEY='VALUE'[KEY='VALUE']... | ||
4423 | const char *p; | ||
4424 | const char *key_start, *key_stop, *val_start, *val_stop; | ||
4425 | |||
4426 | key_start = key_stop = val_start = val_stop = NULL; | ||
4427 | p = ts->style_text; | ||
4428 | while (*p) | ||
4429 | { | ||
4430 | if (!key_start) | ||
4431 | { | ||
4432 | if (!isspace(*p)) | ||
4433 | key_start = p; | ||
4434 | } | ||
4435 | else if (!key_stop) | ||
4436 | { | ||
4437 | if ((*p == '=') || (isspace(*p))) | ||
4438 | key_stop = p; | ||
4439 | } | ||
4440 | else if (!val_start) | ||
4441 | { | ||
4442 | if (((*p) == '\'') && (*(p + 1))) | ||
4443 | val_start = p + 1; | ||
4444 | } | ||
4445 | else if (!val_stop) | ||
4446 | { | ||
4447 | if (((*p) == '\'') && (p > ts->style_text) && (p[-1] != '\\')) | ||
4448 | val_stop = p; | ||
4449 | } | ||
4450 | if ((key_start) && (key_stop) && (val_start) && (val_stop)) | ||
4451 | { | ||
4452 | char *tags, *replaces; | ||
4453 | Evas_Object_Style_Tag *tag; | ||
4454 | size_t tag_len = key_stop - key_start; | ||
4455 | size_t replace_len = val_stop - val_start; | ||
4456 | |||
4457 | tags = malloc(tag_len + 1); | ||
4458 | if (tags) | ||
4459 | { | ||
4460 | memcpy(tags, key_start, tag_len); | ||
4461 | tags[tag_len] = 0; | ||
4462 | } | ||
4463 | |||
4464 | replaces = malloc(replace_len + 1); | ||
4465 | if (replaces) | ||
4466 | { | ||
4467 | memcpy(replaces, val_start, replace_len); | ||
4468 | replaces[replace_len] = 0; | ||
4469 | } | ||
4470 | if ((tags) && (replaces)) | ||
4471 | { | ||
4472 | if (!strcmp(tags, "DEFAULT")) | ||
4473 | { | ||
4474 | ts->default_tag = replaces; | ||
4475 | free(tags); | ||
4476 | } | ||
4477 | else | ||
4478 | { | ||
4479 | tag = calloc(1, sizeof(Evas_Object_Style_Tag)); | ||
4480 | if (tag) | ||
4481 | { | ||
4482 | tag->tag = tags; | ||
4483 | tag->replace = replaces; | ||
4484 | tag->tag_len = tag_len; | ||
4485 | tag->replace_len = replace_len; | ||
4486 | ts->tags = (Evas_Object_Style_Tag *)eina_inlist_append(EINA_INLIST_GET(ts->tags), EINA_INLIST_GET(tag)); | ||
4487 | } | ||
4488 | else | ||
4489 | { | ||
4490 | free(tags); | ||
4491 | free(replaces); | ||
4492 | } | ||
4493 | } | ||
4494 | } | ||
4495 | else | ||
4496 | { | ||
4497 | if (tags) free(tags); | ||
4498 | if (replaces) free(replaces); | ||
4499 | } | ||
4500 | key_start = key_stop = val_start = val_stop = NULL; | ||
4501 | } | ||
4502 | p++; | ||
4503 | } | ||
4504 | } | ||
4505 | } | ||
4506 | |||
4507 | EAPI const char * | ||
4508 | evas_textblock_style_get(const Evas_Textblock_Style *ts) | ||
4509 | { | ||
4510 | if (!ts) return NULL; | ||
4511 | return ts->style_text; | ||
4512 | } | ||
4513 | |||
4514 | /* textblock styles */ | ||
4515 | EAPI void | ||
4516 | evas_object_textblock_style_set(Evas_Object *obj, Evas_Textblock_Style *ts) | ||
4517 | { | ||
4518 | TB_HEAD(); | ||
4519 | if (ts == o->style) return; | ||
4520 | if ((ts) && (ts->delete_me)) return; | ||
4521 | if (o->style) | ||
4522 | { | ||
4523 | Evas_Textblock_Style *old_ts; | ||
4524 | if (o->markup_text) | ||
4525 | { | ||
4526 | free(o->markup_text); | ||
4527 | o->markup_text = NULL; | ||
4528 | } | ||
4529 | |||
4530 | old_ts = o->style; | ||
4531 | old_ts->objects = eina_list_remove(old_ts->objects, obj); | ||
4532 | if ((old_ts->delete_me) && (!old_ts->objects)) | ||
4533 | evas_textblock_style_free(old_ts); | ||
4534 | } | ||
4535 | if (ts) | ||
4536 | { | ||
4537 | ts->objects = eina_list_append(ts->objects, obj); | ||
4538 | } | ||
4539 | o->style = ts; | ||
4540 | |||
4541 | _evas_textblock_invalidate_all(o); | ||
4542 | _evas_textblock_changed(o, obj); | ||
4543 | } | ||
4544 | |||
4545 | EAPI const Evas_Textblock_Style * | ||
4546 | evas_object_textblock_style_get(const Evas_Object *obj) | ||
4547 | { | ||
4548 | TB_HEAD_RETURN(NULL); | ||
4549 | return o->style; | ||
4550 | } | ||
4551 | |||
4552 | EAPI void | ||
4553 | evas_object_textblock_replace_char_set(Evas_Object *obj, const char *ch) | ||
4554 | { | ||
4555 | TB_HEAD(); | ||
4556 | if (o->repch) eina_stringshare_del(o->repch); | ||
4557 | if (ch) o->repch = eina_stringshare_add(ch); | ||
4558 | else o->repch = NULL; | ||
4559 | _evas_textblock_invalidate_all(o); | ||
4560 | _evas_textblock_changed(o, obj); | ||
4561 | } | ||
4562 | |||
4563 | EAPI void | ||
4564 | evas_object_textblock_legacy_newline_set(Evas_Object *obj, Eina_Bool mode) | ||
4565 | { | ||
4566 | TB_HEAD(); | ||
4567 | if (o->legacy_newline == mode) | ||
4568 | return; | ||
4569 | |||
4570 | o->legacy_newline = mode; | ||
4571 | /* FIXME: Should recreate all the textnodes... For now, it's just | ||
4572 | * for new text inserted. */ | ||
4573 | } | ||
4574 | |||
4575 | EAPI Eina_Bool | ||
4576 | evas_object_textblock_legacy_newline_get(const Evas_Object *obj) | ||
4577 | { | ||
4578 | TB_HEAD_RETURN(EINA_FALSE); | ||
4579 | return o->legacy_newline; | ||
4580 | } | ||
4581 | |||
4582 | EAPI void | ||
4583 | evas_object_textblock_valign_set(Evas_Object *obj, double align) | ||
4584 | { | ||
4585 | TB_HEAD(); | ||
4586 | if (align < 0.0) align = 0.0; | ||
4587 | else if (align > 1.0) align = 1.0; | ||
4588 | if (o->valign == align) return; | ||
4589 | o->valign = align; | ||
4590 | _evas_textblock_changed(o, obj); | ||
4591 | } | ||
4592 | |||
4593 | EAPI double | ||
4594 | evas_object_textblock_valign_get(const Evas_Object *obj) | ||
4595 | { | ||
4596 | TB_HEAD_RETURN(0.0); | ||
4597 | return o->valign; | ||
4598 | } | ||
4599 | |||
4600 | EAPI void | ||
4601 | evas_object_textblock_bidi_delimiters_set(Evas_Object *obj, const char *delim) | ||
4602 | { | ||
4603 | TB_HEAD(); | ||
4604 | eina_stringshare_replace(&o->bidi_delimiters, delim); | ||
4605 | } | ||
4606 | |||
4607 | EAPI const char * | ||
4608 | evas_object_textblock_bidi_delimiters_get(const Evas_Object *obj) | ||
4609 | { | ||
4610 | TB_HEAD_RETURN(NULL); | ||
4611 | return o->bidi_delimiters; | ||
4612 | } | ||
4613 | |||
4614 | EAPI const char * | ||
4615 | evas_object_textblock_replace_char_get(Evas_Object *obj) | ||
4616 | { | ||
4617 | TB_HEAD_RETURN(NULL); | ||
4618 | return o->repch; | ||
4619 | } | ||
4620 | |||
4621 | /** | ||
4622 | * @internal | ||
4623 | * Advance p_buff to point after the end of the string. It's used with the | ||
4624 | * @ref escaped_strings[] variable. | ||
4625 | * | ||
4626 | * @param p_buff the pointer to the current string. | ||
4627 | */ | ||
4628 | static inline void | ||
4629 | _escaped_advance_after_end_of_string(const char **p_buf) | ||
4630 | { | ||
4631 | while (**p_buf != 0) (*p_buf)++; | ||
4632 | (*p_buf)++; | ||
4633 | } | ||
4634 | |||
4635 | /** | ||
4636 | * @internal | ||
4637 | * Advance p_buff to point after the end of the string. It's used with the | ||
4638 | * @ref escaped_strings[] variable. Also chec if matches. | ||
4639 | * FIXME: doc. | ||
4640 | * | ||
4641 | * @param p_buff the pointer to the current string. | ||
4642 | */ | ||
4643 | static inline int | ||
4644 | _escaped_is_eq_and_advance(const char *s, const char *s_end, | ||
4645 | const char **p_m, const char *m_end) | ||
4646 | { | ||
4647 | Eina_Bool reached_end; | ||
4648 | for (;((s < s_end) && (*p_m < m_end)); s++, (*p_m)++) | ||
4649 | { | ||
4650 | if (*s != **p_m) | ||
4651 | { | ||
4652 | _escaped_advance_after_end_of_string(p_m); | ||
4653 | return 0; | ||
4654 | } | ||
4655 | } | ||
4656 | |||
4657 | reached_end = !**p_m; | ||
4658 | if (*p_m < m_end) | ||
4659 | _escaped_advance_after_end_of_string(p_m); | ||
4660 | |||
4661 | return ((s == s_end) && reached_end); | ||
4662 | } | ||
4663 | |||
4664 | /** | ||
4665 | * @internal | ||
4666 | * | ||
4667 | * @param s the string to match | ||
4668 | */ | ||
4669 | static inline const char * | ||
4670 | _escaped_char_match(const char *s, int *adv) | ||
4671 | { | ||
4672 | const char *map_itr, *map_end, *mc, *sc; | ||
4673 | |||
4674 | map_itr = escape_strings; | ||
4675 | map_end = map_itr + sizeof(escape_strings); | ||
4676 | |||
4677 | while (map_itr < map_end) | ||
4678 | { | ||
4679 | const char *escape; | ||
4680 | int match; | ||
4681 | |||
4682 | escape = map_itr; | ||
4683 | _escaped_advance_after_end_of_string(&map_itr); | ||
4684 | if (map_itr >= map_end) break; | ||
4685 | |||
4686 | mc = map_itr; | ||
4687 | sc = s; | ||
4688 | match = 1; | ||
4689 | while ((*mc) && (*sc)) | ||
4690 | { | ||
4691 | if ((unsigned char)*sc < (unsigned char)*mc) return NULL; | ||
4692 | if (*sc != *mc) match = 0; | ||
4693 | mc++; | ||
4694 | sc++; | ||
4695 | } | ||
4696 | if (match) | ||
4697 | { | ||
4698 | *adv = mc - map_itr; | ||
4699 | return escape; | ||
4700 | } | ||
4701 | _escaped_advance_after_end_of_string(&map_itr); | ||
4702 | } | ||
4703 | return NULL; | ||
4704 | } | ||
4705 | |||
4706 | /** | ||
4707 | * @internal | ||
4708 | * FIXME: TBD. | ||
4709 | * | ||
4710 | * @param s the string to match | ||
4711 | */ | ||
4712 | static inline const char * | ||
4713 | _escaped_char_get(const char *s, const char *s_end) | ||
4714 | { | ||
4715 | /* Handle numeric escape codes. */ | ||
4716 | if (s[1] == '#') | ||
4717 | { | ||
4718 | static char utf8_escape[7]; /* Support up to 6 bytes utf8 */ | ||
4719 | char ustr[10]; | ||
4720 | Eina_Unicode uchar[2] = { 0, 0 }; | ||
4721 | char *utf8_char; | ||
4722 | size_t len = 0; | ||
4723 | int base = 10; | ||
4724 | s += 2; /* Skip "&#" */ | ||
4725 | |||
4726 | if (tolower(*s) == 'x') | ||
4727 | { | ||
4728 | s++; | ||
4729 | base = 16; | ||
4730 | } | ||
4731 | |||
4732 | len = s_end - s; | ||
4733 | if (len >= sizeof(ustr) + 1) | ||
4734 | len = sizeof(ustr); | ||
4735 | |||
4736 | memcpy(ustr, s, len); | ||
4737 | ustr[len] = '\0'; | ||
4738 | uchar[0] = strtol(ustr, NULL, base); | ||
4739 | |||
4740 | if (uchar[0] == 0) | ||
4741 | return NULL; | ||
4742 | |||
4743 | utf8_char = eina_unicode_unicode_to_utf8(uchar, NULL); | ||
4744 | strcpy(utf8_escape, utf8_char); | ||
4745 | free(utf8_char); | ||
4746 | |||
4747 | return utf8_escape; | ||
4748 | } | ||
4749 | else | ||
4750 | { | ||
4751 | const char *map_itr, *map_end; | ||
4752 | |||
4753 | map_itr = escape_strings; | ||
4754 | map_end = map_itr + sizeof(escape_strings); | ||
4755 | |||
4756 | while (map_itr < map_end) | ||
4757 | { | ||
4758 | if (_escaped_is_eq_and_advance(s, s_end, &map_itr, map_end)) | ||
4759 | return map_itr; | ||
4760 | if (map_itr < map_end) | ||
4761 | _escaped_advance_after_end_of_string(&map_itr); | ||
4762 | } | ||
4763 | } | ||
4764 | |||
4765 | return NULL; | ||
4766 | } | ||
4767 | |||
4768 | EAPI const char * | ||
4769 | evas_textblock_escape_string_get(const char *escape) | ||
4770 | { | ||
4771 | /* & -> & */ | ||
4772 | return _escaped_char_get(escape, escape + strlen(escape)); | ||
4773 | } | ||
4774 | |||
4775 | EAPI const char * | ||
4776 | evas_textblock_escape_string_range_get(const char *escape_start, const char *escape_end) | ||
4777 | { | ||
4778 | return _escaped_char_get(escape_start, escape_end); | ||
4779 | } | ||
4780 | |||
4781 | EAPI const char * | ||
4782 | evas_textblock_string_escape_get(const char *string, int *len_ret) | ||
4783 | { | ||
4784 | /* & -> & */ | ||
4785 | return _escaped_char_match(string, len_ret); | ||
4786 | } | ||
4787 | |||
4788 | /** | ||
4789 | * @internal | ||
4790 | * Appends the escaped char beteewn s and s_end to the curosr | ||
4791 | * | ||
4792 | * | ||
4793 | * @param s the start of the string | ||
4794 | * @param s_end the end of the string. | ||
4795 | */ | ||
4796 | static inline void | ||
4797 | _append_escaped_char(Evas_Textblock_Cursor *cur, const char *s, | ||
4798 | const char *s_end) | ||
4799 | { | ||
4800 | const char *escape; | ||
4801 | |||
4802 | escape = _escaped_char_get(s, s_end); | ||
4803 | if (escape) | ||
4804 | evas_textblock_cursor_text_append(cur, escape); | ||
4805 | } | ||
4806 | |||
4807 | /** | ||
4808 | * @internal | ||
4809 | * prepends the escaped char beteewn s and s_end to the curosr | ||
4810 | * | ||
4811 | * | ||
4812 | * @param s the start of the string | ||
4813 | * @param s_end the end of the string. | ||
4814 | */ | ||
4815 | static inline void | ||
4816 | _prepend_escaped_char(Evas_Textblock_Cursor *cur, const char *s, | ||
4817 | const char *s_end) | ||
4818 | { | ||
4819 | const char *escape; | ||
4820 | |||
4821 | escape = _escaped_char_get(s, s_end); | ||
4822 | if (escape) | ||
4823 | evas_textblock_cursor_text_prepend(cur, escape); | ||
4824 | } | ||
4825 | |||
4826 | |||
4827 | EAPI void | ||
4828 | evas_object_textblock_text_markup_set(Evas_Object *obj, const char *text) | ||
4829 | { | ||
4830 | TB_HEAD(); | ||
4831 | if ((text != o->markup_text) && (o->markup_text)) | ||
4832 | { | ||
4833 | free(o->markup_text); | ||
4834 | o->markup_text = NULL; | ||
4835 | } | ||
4836 | _nodes_clear(obj); | ||
4837 | if (!o->style) | ||
4838 | { | ||
4839 | if (text != o->markup_text) | ||
4840 | { | ||
4841 | if (text) o->markup_text = strdup(text); | ||
4842 | } | ||
4843 | return; | ||
4844 | } | ||
4845 | evas_textblock_cursor_paragraph_first(o->cursor); | ||
4846 | |||
4847 | evas_object_textblock_text_markup_prepend(o->cursor, text); | ||
4848 | /* Point all the cursors to the starrt */ | ||
4849 | { | ||
4850 | Eina_List *l; | ||
4851 | Evas_Textblock_Cursor *data; | ||
4852 | |||
4853 | evas_textblock_cursor_paragraph_first(o->cursor); | ||
4854 | EINA_LIST_FOREACH(o->cursors, l, data) | ||
4855 | evas_textblock_cursor_paragraph_first(data); | ||
4856 | } | ||
4857 | } | ||
4858 | |||
4859 | EAPI void | ||
4860 | evas_object_textblock_text_markup_prepend(Evas_Textblock_Cursor *cur, const char *text) | ||
4861 | { | ||
4862 | Evas_Object *obj = cur->obj; | ||
4863 | TB_HEAD(); | ||
4864 | if (text) | ||
4865 | { | ||
4866 | char *s, *p; | ||
4867 | char *tag_start, *tag_end, *esc_start, *esc_end; | ||
4868 | |||
4869 | tag_start = tag_end = esc_start = esc_end = NULL; | ||
4870 | p = (char *)text; | ||
4871 | s = p; | ||
4872 | /* This loop goes through all of the mark up text until it finds format | ||
4873 | * tags, escape sequences or the terminating NULL. When it finds either | ||
4874 | * of those, it appends the text found up until that point to the textblock | ||
4875 | * proccesses whatever found. It repeats itself until the termainating | ||
4876 | * NULL is reached. */ | ||
4877 | for (;;) | ||
4878 | { | ||
4879 | /* If we got to the end of string or just finished/started tag | ||
4880 | * or escape sequence handling. */ | ||
4881 | if ((*p == 0) || | ||
4882 | (tag_end) || (esc_end) || | ||
4883 | (tag_start) || (esc_start)) | ||
4884 | { | ||
4885 | if (tag_end) | ||
4886 | { | ||
4887 | /* If we reached to a tag ending, analyze the tag */ | ||
4888 | char *ttag; | ||
4889 | size_t ttag_len = tag_end - tag_start; | ||
4890 | |||
4891 | |||
4892 | ttag = malloc(ttag_len + 1); | ||
4893 | if (ttag) | ||
4894 | { | ||
4895 | memcpy(ttag, tag_start, ttag_len); | ||
4896 | ttag[ttag_len] = 0; | ||
4897 | evas_textblock_cursor_format_prepend(cur, ttag); | ||
4898 | free(ttag); | ||
4899 | } | ||
4900 | tag_start = tag_end = NULL; | ||
4901 | } | ||
4902 | else if (esc_end) | ||
4903 | { | ||
4904 | _prepend_escaped_char(cur, esc_start, esc_end + 1); | ||
4905 | esc_start = esc_end = NULL; | ||
4906 | } | ||
4907 | else if (*p == 0) | ||
4908 | { | ||
4909 | _prepend_text_run(cur, s, p); | ||
4910 | s = NULL; | ||
4911 | } | ||
4912 | if (*p == 0) | ||
4913 | break; | ||
4914 | } | ||
4915 | if (*p == '<') | ||
4916 | { | ||
4917 | if (!esc_start) | ||
4918 | { | ||
4919 | /* Append the text prior to this to the textblock and mark | ||
4920 | * the start of the tag */ | ||
4921 | tag_start = p; | ||
4922 | tag_end = NULL; | ||
4923 | _prepend_text_run(cur, s, p); | ||
4924 | s = NULL; | ||
4925 | } | ||
4926 | } | ||
4927 | else if (*p == '>') | ||
4928 | { | ||
4929 | if (tag_start) | ||
4930 | { | ||
4931 | tag_end = p + 1; | ||
4932 | s = p + 1; | ||
4933 | } | ||
4934 | } | ||
4935 | else if (*p == '&') | ||
4936 | { | ||
4937 | if (!tag_start) | ||
4938 | { | ||
4939 | /* Append the text prior to this to the textblock and mark | ||
4940 | * the start of the escape sequence */ | ||
4941 | esc_start = p; | ||
4942 | esc_end = NULL; | ||
4943 | _prepend_text_run(cur, s, p); | ||
4944 | s = NULL; | ||
4945 | } | ||
4946 | } | ||
4947 | else if (*p == ';') | ||
4948 | { | ||
4949 | if (esc_start) | ||
4950 | { | ||
4951 | esc_end = p; | ||
4952 | s = p + 1; | ||
4953 | } | ||
4954 | } | ||
4955 | /* Unicode object replcament char */ | ||
4956 | else if (!strncmp("\xEF\xBF\xBC", p, 3)) | ||
4957 | { | ||
4958 | /*FIXME: currently just remove them, maybe do something | ||
4959 | * fancier in the future, atm it breaks if this char | ||
4960 | * is inside <> */ | ||
4961 | _prepend_text_run(cur, s, p); | ||
4962 | p += 2; /* it's also advanced later in this loop need +3 | ||
4963 | * in total*/ | ||
4964 | s = p + 1; /* One after the end of the replacement char */ | ||
4965 | } | ||
4966 | p++; | ||
4967 | } | ||
4968 | } | ||
4969 | _evas_textblock_changed(o, obj); | ||
4970 | } | ||
4971 | |||
4972 | |||
4973 | /** | ||
4974 | * @internal | ||
4975 | * An helper function to markup get. Appends the format from fnode to the strbugf txt. | ||
4976 | * | ||
4977 | * @param o the textblock object. | ||
4978 | * @param txt the strbuf to append to. | ||
4979 | * @param fnode the format node to process. | ||
4980 | */ | ||
4981 | static void | ||
4982 | _markup_get_format_append(Evas_Object_Textblock *o __UNUSED__, Eina_Strbuf *txt, Evas_Object_Textblock_Node_Format *fnode) | ||
4983 | { | ||
4984 | eina_strbuf_append_char(txt, '<'); | ||
4985 | { | ||
4986 | const char *s; | ||
4987 | int pop = 0; | ||
4988 | |||
4989 | // FIXME: need to escape | ||
4990 | s = fnode->orig_format; | ||
4991 | if (*s == '-') pop = 1; | ||
4992 | while ((*s == ' ') || (*s == '+') || (*s == '-')) s++; | ||
4993 | if (pop) eina_strbuf_append_char(txt, '/'); | ||
4994 | eina_strbuf_append(txt, s); | ||
4995 | } | ||
4996 | eina_strbuf_append_char(txt, '>'); | ||
4997 | } | ||
4998 | |||
4999 | /** | ||
5000 | * @internal | ||
5001 | * An helper function to markup get. Appends the text in text. | ||
5002 | * | ||
5003 | * @param txt the strbuf to append to. | ||
5004 | * @param text the text to process. | ||
5005 | */ | ||
5006 | static void | ||
5007 | _markup_get_text_append(Eina_Strbuf *txt, const Eina_Unicode *text) | ||
5008 | { | ||
5009 | char *p = eina_unicode_unicode_to_utf8(text, NULL); | ||
5010 | char *base = p; | ||
5011 | while (*p) | ||
5012 | { | ||
5013 | const char *escape; | ||
5014 | int adv; | ||
5015 | |||
5016 | escape = _escaped_char_match(p, &adv); | ||
5017 | if (escape) | ||
5018 | { | ||
5019 | p += adv; | ||
5020 | eina_strbuf_append(txt, escape); | ||
5021 | } | ||
5022 | else | ||
5023 | { | ||
5024 | eina_strbuf_append_char(txt, *p); | ||
5025 | p++; | ||
5026 | } | ||
5027 | } | ||
5028 | free(base); | ||
5029 | } | ||
5030 | EAPI const char * | ||
5031 | evas_object_textblock_text_markup_get(const Evas_Object *obj) | ||
5032 | { | ||
5033 | Evas_Object_Textblock_Node_Text *n; | ||
5034 | Eina_Strbuf *txt = NULL; | ||
5035 | |||
5036 | TB_HEAD_RETURN(NULL); | ||
5037 | if (o->markup_text) return(o->markup_text); | ||
5038 | txt = eina_strbuf_new(); | ||
5039 | EINA_INLIST_FOREACH(o->text_nodes, n) | ||
5040 | { | ||
5041 | Evas_Object_Textblock_Node_Format *fnode; | ||
5042 | Eina_Unicode *text_base, *text; | ||
5043 | int off; | ||
5044 | |||
5045 | /* For each text node to thorugh all of it's format nodes | ||
5046 | * append text from the start to the offset of the next format | ||
5047 | * using the last format got. if needed it also creates format items | ||
5048 | * this is the core algorithm of the layout mechanism. | ||
5049 | * Skip the unicode replacement chars when there are because | ||
5050 | * we don't want to print them. */ | ||
5051 | text_base = text = | ||
5052 | eina_unicode_strndup(eina_ustrbuf_string_get(n->unicode), | ||
5053 | eina_ustrbuf_length_get(n->unicode)); | ||
5054 | fnode = n->format_node; | ||
5055 | off = 0; | ||
5056 | while (fnode && (fnode->text_node == n)) | ||
5057 | { | ||
5058 | Eina_Unicode tmp_ch; | ||
5059 | off += fnode->offset; | ||
5060 | /* No need to skip on the first run */ | ||
5061 | tmp_ch = text[off]; | ||
5062 | text[off] = 0; /* Null terminate the part of the string */ | ||
5063 | _markup_get_text_append(txt, text); | ||
5064 | _markup_get_format_append(o, txt, fnode); | ||
5065 | text[off] = tmp_ch; /* Restore the char */ | ||
5066 | text += off; | ||
5067 | if (fnode->visible) | ||
5068 | { | ||
5069 | off = -1; | ||
5070 | text++; | ||
5071 | } | ||
5072 | else | ||
5073 | { | ||
5074 | off = 0; | ||
5075 | } | ||
5076 | fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
5077 | } | ||
5078 | /* Add the rest, skip replacement */ | ||
5079 | _markup_get_text_append(txt, text); | ||
5080 | free(text_base); | ||
5081 | } | ||
5082 | |||
5083 | |||
5084 | o->markup_text = eina_strbuf_string_steal(txt); | ||
5085 | eina_strbuf_free(txt); | ||
5086 | return o->markup_text; | ||
5087 | } | ||
5088 | |||
5089 | /* cursors */ | ||
5090 | |||
5091 | /** | ||
5092 | * @internal | ||
5093 | * Merge the current node with the next, no need to remove PS, already | ||
5094 | * not there. | ||
5095 | * | ||
5096 | * @param o the text block object. | ||
5097 | * @param to merge into to. | ||
5098 | */ | ||
5099 | static void | ||
5100 | _evas_textblock_nodes_merge(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *to) | ||
5101 | { | ||
5102 | Evas_Object_Textblock_Node_Format *itr; | ||
5103 | Evas_Object_Textblock_Node_Format *pnode; | ||
5104 | Evas_Object_Textblock_Node_Text *from; | ||
5105 | const Eina_Unicode *text; | ||
5106 | int to_len, len; | ||
5107 | |||
5108 | if (!to) return; | ||
5109 | from = _NODE_TEXT(EINA_INLIST_GET(to)->next); | ||
5110 | |||
5111 | to_len = eina_ustrbuf_length_get(to->unicode); | ||
5112 | text = eina_ustrbuf_string_get(from->unicode); | ||
5113 | len = eina_ustrbuf_length_get(from->unicode); | ||
5114 | eina_ustrbuf_append_length(to->unicode, text, len); | ||
5115 | |||
5116 | itr = from->format_node; | ||
5117 | if (itr && (itr->text_node == from)) | ||
5118 | { | ||
5119 | pnode = _NODE_FORMAT(EINA_INLIST_GET(itr)->prev); | ||
5120 | if (pnode && (pnode->text_node == to)) | ||
5121 | { | ||
5122 | itr->offset += to_len - _evas_textblock_node_format_pos_get(pnode); | ||
5123 | } | ||
5124 | else | ||
5125 | { | ||
5126 | itr->offset += to_len; | ||
5127 | } | ||
5128 | } | ||
5129 | |||
5130 | while (itr && (itr->text_node == from)) | ||
5131 | { | ||
5132 | itr->text_node = to; | ||
5133 | itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next); | ||
5134 | } | ||
5135 | if (!to->format_node || (to->format_node->text_node != to)) | ||
5136 | { | ||
5137 | to->format_node = from->format_node; | ||
5138 | } | ||
5139 | |||
5140 | /* When it comes to how we handle it, merging is like removing both nodes | ||
5141 | * and creating a new one, se we need to do the needed cleanups. */ | ||
5142 | if (to->par) | ||
5143 | to->par->text_node = NULL; | ||
5144 | to->par = NULL; | ||
5145 | |||
5146 | to->is_new = EINA_TRUE; | ||
5147 | |||
5148 | _evas_textblock_cursors_set_node(o, from, to); | ||
5149 | _evas_textblock_node_text_remove(o, from); | ||
5150 | } | ||
5151 | |||
5152 | /** | ||
5153 | * @internal | ||
5154 | * Merge the current node with the next, no need to remove PS, already | ||
5155 | * not there. | ||
5156 | * | ||
5157 | * @param cur the cursor that points to the current node | ||
5158 | */ | ||
5159 | static void | ||
5160 | _evas_textblock_cursor_nodes_merge(Evas_Textblock_Cursor *cur) | ||
5161 | { | ||
5162 | Evas_Object_Textblock_Node_Text *nnode; | ||
5163 | Evas_Object_Textblock *o; | ||
5164 | int len; | ||
5165 | if (!cur) return; | ||
5166 | |||
5167 | len = eina_ustrbuf_length_get(cur->node->unicode); | ||
5168 | |||
5169 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
5170 | nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next); | ||
5171 | _evas_textblock_nodes_merge(o, cur->node); | ||
5172 | _evas_textblock_cursors_update_offset(cur, nnode, 0, len); | ||
5173 | _evas_textblock_cursors_set_node(o, nnode, cur->node); | ||
5174 | if (nnode == o->cursor->node) | ||
5175 | { | ||
5176 | o->cursor->node = cur->node; | ||
5177 | o->cursor->pos += len; | ||
5178 | } | ||
5179 | } | ||
5180 | |||
5181 | /** | ||
5182 | * @internal | ||
5183 | * Return the format at a specific position. | ||
5184 | * | ||
5185 | * @param cur the cursor to the position. | ||
5186 | * @return the format node at the specific position or NULL if not found. | ||
5187 | */ | ||
5188 | static Evas_Object_Textblock_Node_Format * | ||
5189 | _evas_textblock_cursor_node_format_at_pos_get(const Evas_Textblock_Cursor *cur) | ||
5190 | { | ||
5191 | Evas_Object_Textblock_Node_Format *node; | ||
5192 | Evas_Object_Textblock_Node_Format *itr; | ||
5193 | int position = 0; | ||
5194 | |||
5195 | if (!cur->node) return NULL; | ||
5196 | |||
5197 | node = cur->node->format_node; | ||
5198 | if (!node) return NULL; | ||
5199 | /* If there is no exclusive format node to this paragraph return the | ||
5200 | * previous's node */ | ||
5201 | /* Find the main format node */ | ||
5202 | EINA_INLIST_FOREACH(node, itr) | ||
5203 | { | ||
5204 | if (itr->text_node != cur->node) | ||
5205 | { | ||
5206 | return NULL; | ||
5207 | } | ||
5208 | if ((position + itr->offset) == cur->pos) | ||
5209 | { | ||
5210 | return itr; | ||
5211 | } | ||
5212 | position += itr->offset; | ||
5213 | } | ||
5214 | return NULL; | ||
5215 | } | ||
5216 | |||
5217 | /** | ||
5218 | * @internal | ||
5219 | * Return the last format node at the position of the format node n. | ||
5220 | * | ||
5221 | * @param n a format node at the position. | ||
5222 | * @return the last format node at the position of n. | ||
5223 | */ | ||
5224 | static Evas_Object_Textblock_Node_Format * | ||
5225 | _evas_textblock_node_format_last_at_off(const Evas_Object_Textblock_Node_Format *n) | ||
5226 | { | ||
5227 | const Evas_Object_Textblock_Node_Format *nnode; | ||
5228 | const Evas_Object_Textblock_Node_Text *tnode; | ||
5229 | if (!n) return NULL; | ||
5230 | nnode = n; | ||
5231 | tnode = n->text_node; | ||
5232 | do | ||
5233 | { | ||
5234 | n = nnode; | ||
5235 | nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next); | ||
5236 | } | ||
5237 | while (nnode && (nnode->text_node == tnode) && (nnode->offset == 0)); | ||
5238 | |||
5239 | return (Evas_Object_Textblock_Node_Format *) n; | ||
5240 | } | ||
5241 | |||
5242 | /** | ||
5243 | * @internal | ||
5244 | * Returns the visible format at a specific location. | ||
5245 | * | ||
5246 | * @param n a format at the specific position. | ||
5247 | * @return the format node at the specific position or NULL if not found. | ||
5248 | */ | ||
5249 | static Evas_Object_Textblock_Node_Format * | ||
5250 | _evas_textblock_node_visible_at_pos_get(const Evas_Object_Textblock_Node_Format *n) | ||
5251 | { | ||
5252 | const Evas_Object_Textblock_Node_Format *nnode; | ||
5253 | if (!n) return NULL; | ||
5254 | /* The visible format is the last one, because it inserts a replacement | ||
5255 | * char that advances the next formats. */ | ||
5256 | |||
5257 | nnode = n; | ||
5258 | do | ||
5259 | { | ||
5260 | n = nnode; | ||
5261 | if (n->visible) return (Evas_Object_Textblock_Node_Format *) n; | ||
5262 | nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next); | ||
5263 | } | ||
5264 | while (nnode && (nnode->offset == 0)); | ||
5265 | |||
5266 | return NULL; | ||
5267 | } | ||
5268 | |||
5269 | /** | ||
5270 | * @internal | ||
5271 | * Return the last format that applies to a specific cursor or at the specific | ||
5272 | * position the cursor points to. This means either a cursor at or before the | ||
5273 | * position of the cursor in the text node is returned or the previous's text | ||
5274 | * node's format node. | ||
5275 | * | ||
5276 | * @param cur the position to look at. | ||
5277 | * @return the format node found. | ||
5278 | */ | ||
5279 | static Evas_Object_Textblock_Node_Format * | ||
5280 | _evas_textblock_cursor_node_format_before_or_at_pos_get(const Evas_Textblock_Cursor *cur) | ||
5281 | { | ||
5282 | Evas_Object_Textblock_Node_Format *node, *pitr = NULL; | ||
5283 | Evas_Object_Textblock_Node_Format *itr; | ||
5284 | size_t position = 0; | ||
5285 | |||
5286 | if (!cur->node) return NULL; | ||
5287 | |||
5288 | node = cur->node->format_node; | ||
5289 | if (!node) return NULL; | ||
5290 | /* If there is no exclusive format node to this paragraph return the | ||
5291 | * previous's node */ | ||
5292 | if (node->text_node != cur->node) | ||
5293 | { | ||
5294 | return node; | ||
5295 | } | ||
5296 | else if (node->offset > cur->pos) | ||
5297 | { | ||
5298 | return _NODE_FORMAT(EINA_INLIST_GET(node)->prev); | ||
5299 | } | ||
5300 | /* Find the main format node */ | ||
5301 | pitr = _NODE_FORMAT(EINA_INLIST_GET(node)->prev); | ||
5302 | EINA_INLIST_FOREACH(node, itr) | ||
5303 | { | ||
5304 | if ((itr->text_node != cur->node) || | ||
5305 | ((position + itr->offset) > cur->pos)) | ||
5306 | { | ||
5307 | return pitr; | ||
5308 | } | ||
5309 | else if ((position + itr->offset) == cur->pos) | ||
5310 | { | ||
5311 | return itr; | ||
5312 | } | ||
5313 | pitr = itr; | ||
5314 | position += itr->offset; | ||
5315 | } | ||
5316 | return pitr; | ||
5317 | } | ||
5318 | |||
5319 | /** | ||
5320 | * @internal | ||
5321 | * Find the layout item and line that match the cursor. | ||
5322 | * | ||
5323 | * @param cur the cursor we are currently at. - NOT NULL. | ||
5324 | * @param[out] lnr the line found - not null. | ||
5325 | * @param[out] itr the item found - not null. | ||
5326 | * @return EINA_TRUE if we matched the previous format, EINA_FALSE otherwise. | ||
5327 | */ | ||
5328 | static Eina_Bool | ||
5329 | _find_layout_item_match(const Evas_Textblock_Cursor *cur, Evas_Object_Textblock_Line **lnr, Evas_Object_Textblock_Item **itr) | ||
5330 | { | ||
5331 | Evas_Textblock_Cursor cur2; | ||
5332 | Eina_Bool previous_format = EINA_FALSE; | ||
5333 | |||
5334 | cur2.obj = cur->obj; | ||
5335 | evas_textblock_cursor_copy(cur, &cur2); | ||
5336 | if (cur2.pos > 0) | ||
5337 | { | ||
5338 | cur2.pos--; | ||
5339 | } | ||
5340 | |||
5341 | if (_evas_textblock_cursor_is_at_the_end(cur) && | ||
5342 | evas_textblock_cursor_format_is_visible_get(&cur2)) | ||
5343 | { | ||
5344 | _find_layout_item_line_match(cur2.obj, cur2.node, cur2.pos, lnr, itr); | ||
5345 | previous_format = EINA_TRUE; | ||
5346 | } | ||
5347 | else | ||
5348 | { | ||
5349 | _find_layout_item_line_match(cur->obj, cur->node, cur->pos, lnr, itr); | ||
5350 | } | ||
5351 | return previous_format; | ||
5352 | } | ||
5353 | |||
5354 | EAPI Evas_Textblock_Cursor * | ||
5355 | evas_object_textblock_cursor_get(const Evas_Object *obj) | ||
5356 | { | ||
5357 | TB_HEAD_RETURN(NULL); | ||
5358 | return o->cursor; | ||
5359 | } | ||
5360 | |||
5361 | EAPI Evas_Textblock_Cursor * | ||
5362 | evas_object_textblock_cursor_new(const Evas_Object *obj) | ||
5363 | { | ||
5364 | Evas_Textblock_Cursor *cur; | ||
5365 | |||
5366 | TB_HEAD_RETURN(NULL); | ||
5367 | cur = calloc(1, sizeof(Evas_Textblock_Cursor)); | ||
5368 | cur->obj = (Evas_Object *) obj; | ||
5369 | cur->node = o->text_nodes; | ||
5370 | cur->pos = 0; | ||
5371 | |||
5372 | o->cursors = eina_list_append(o->cursors, cur); | ||
5373 | return cur; | ||
5374 | } | ||
5375 | |||
5376 | EAPI void | ||
5377 | evas_textblock_cursor_free(Evas_Textblock_Cursor *cur) | ||
5378 | { | ||
5379 | Evas_Object_Textblock *o; | ||
5380 | |||
5381 | if (!cur) return; | ||
5382 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
5383 | if (cur == o->cursor) return; | ||
5384 | o->cursors = eina_list_remove(o->cursors, cur); | ||
5385 | free(cur); | ||
5386 | } | ||
5387 | |||
5388 | EAPI Eina_Bool | ||
5389 | evas_textblock_cursor_is_format(const Evas_Textblock_Cursor *cur) | ||
5390 | { | ||
5391 | if (!cur || !cur->node) return EINA_FALSE; | ||
5392 | if (evas_textblock_cursor_format_is_visible_get(cur)) return EINA_TRUE; | ||
5393 | return (_evas_textblock_cursor_node_format_at_pos_get(cur)) ? | ||
5394 | EINA_TRUE : EINA_FALSE; | ||
5395 | } | ||
5396 | |||
5397 | EAPI const Eina_List * | ||
5398 | evas_textblock_node_format_list_get(const Evas_Object *obj, const char *anchor) | ||
5399 | { | ||
5400 | TB_HEAD_RETURN(NULL); | ||
5401 | if (!strcmp(anchor, "a")) | ||
5402 | return o->anchors_a; | ||
5403 | else if (!strcmp(anchor, "item")) | ||
5404 | return o->anchors_item; | ||
5405 | |||
5406 | return NULL; | ||
5407 | } | ||
5408 | |||
5409 | EAPI const Evas_Object_Textblock_Node_Format * | ||
5410 | evas_textblock_node_format_first_get(const Evas_Object *obj) | ||
5411 | { | ||
5412 | TB_HEAD_RETURN(NULL); | ||
5413 | return o->format_nodes; | ||
5414 | } | ||
5415 | |||
5416 | EAPI const Evas_Object_Textblock_Node_Format * | ||
5417 | evas_textblock_node_format_last_get(const Evas_Object *obj) | ||
5418 | { | ||
5419 | TB_HEAD_RETURN(NULL); | ||
5420 | if (o->format_nodes) | ||
5421 | { | ||
5422 | return _NODE_FORMAT(EINA_INLIST_GET(o->format_nodes)->last); | ||
5423 | } | ||
5424 | return NULL; | ||
5425 | } | ||
5426 | |||
5427 | EAPI const Evas_Object_Textblock_Node_Format * | ||
5428 | evas_textblock_node_format_next_get(const Evas_Object_Textblock_Node_Format *n) | ||
5429 | { | ||
5430 | return _NODE_FORMAT(EINA_INLIST_GET(n)->next); | ||
5431 | } | ||
5432 | |||
5433 | EAPI const Evas_Object_Textblock_Node_Format * | ||
5434 | evas_textblock_node_format_prev_get(const Evas_Object_Textblock_Node_Format *n) | ||
5435 | { | ||
5436 | return _NODE_FORMAT(EINA_INLIST_GET(n)->prev); | ||
5437 | } | ||
5438 | |||
5439 | EAPI void | ||
5440 | evas_textblock_node_format_remove_pair(Evas_Object *obj, | ||
5441 | Evas_Object_Textblock_Node_Format *n) | ||
5442 | { | ||
5443 | Evas_Object_Textblock_Node_Text *tnode1; | ||
5444 | Evas_Object_Textblock_Node_Format *fmt, *found_node = NULL; | ||
5445 | Eina_List *fstack = NULL; | ||
5446 | TB_HEAD(); | ||
5447 | |||
5448 | if (!n) return; | ||
5449 | |||
5450 | fmt = n; | ||
5451 | |||
5452 | do | ||
5453 | { | ||
5454 | const char *fstr = fmt->orig_format; | ||
5455 | |||
5456 | if (fstr && (*fstr == '+')) | ||
5457 | { | ||
5458 | fstack = eina_list_prepend(fstack, fmt); | ||
5459 | } | ||
5460 | else if (fstr && (*fstr == '-')) | ||
5461 | { | ||
5462 | size_t fstr_len; | ||
5463 | /* Skip the '-' */ | ||
5464 | fstr++; | ||
5465 | fstr_len = strlen(fstr); | ||
5466 | /* Generic popper, just pop */ | ||
5467 | if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0]) | ||
5468 | { | ||
5469 | fstack = eina_list_remove_list(fstack, fstack); | ||
5470 | if (!fstack) | ||
5471 | { | ||
5472 | found_node = fmt; | ||
5473 | goto found; | ||
5474 | } | ||
5475 | } | ||
5476 | /* Find the matching format and pop it, if the matching format | ||
5477 | * is out format, i.e the last one, pop and break. */ | ||
5478 | else | ||
5479 | { | ||
5480 | Eina_List *i; | ||
5481 | Evas_Object_Textblock_Node_Format *fnode; | ||
5482 | EINA_LIST_FOREACH(fstack, i, fnode) | ||
5483 | { | ||
5484 | if (_FORMAT_IS_CLOSER_OF( | ||
5485 | fnode->orig_format, fstr, fstr_len)) | ||
5486 | { | ||
5487 | /* Last one, this is our item! */ | ||
5488 | if (!eina_list_next(i)) | ||
5489 | { | ||
5490 | found_node = fmt; | ||
5491 | goto found; | ||
5492 | } | ||
5493 | fstack = eina_list_remove_list(fstack, i); | ||
5494 | break; | ||
5495 | } | ||
5496 | } | ||
5497 | } | ||
5498 | } | ||
5499 | |||
5500 | fmt = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next); | ||
5501 | } | ||
5502 | while (fmt && fstack); | ||
5503 | |||
5504 | found: | ||
5505 | |||
5506 | fstack = eina_list_free(fstack); | ||
5507 | |||
5508 | if (n->visible) | ||
5509 | { | ||
5510 | size_t ind = _evas_textblock_node_format_pos_get(n); | ||
5511 | const char *format = n->format; | ||
5512 | Evas_Textblock_Cursor cur; | ||
5513 | cur.obj = obj; | ||
5514 | |||
5515 | eina_ustrbuf_remove(n->text_node->unicode, ind, ind + 1); | ||
5516 | if (format && _IS_PARAGRAPH_SEPARATOR(o, format)) | ||
5517 | { | ||
5518 | evas_textblock_cursor_at_format_set(&cur, n); | ||
5519 | _evas_textblock_cursor_nodes_merge(&cur); | ||
5520 | } | ||
5521 | _evas_textblock_cursors_update_offset(&cur, n->text_node, ind, -1); | ||
5522 | } | ||
5523 | tnode1 = n->text_node; | ||
5524 | _evas_textblock_node_format_remove(o, n, 0); | ||
5525 | if (found_node && (found_node != n)) | ||
5526 | { | ||
5527 | Evas_Object_Textblock_Node_Text *tnode2; | ||
5528 | tnode2 = found_node->text_node; | ||
5529 | /* found_node can never be visible! (it's the closing format) */ | ||
5530 | _evas_textblock_node_format_remove(o, found_node, 0); | ||
5531 | |||
5532 | /* FIXME: Should be unified in the layout, for example, added to a list | ||
5533 | * that checks this kind of removals. But until then, this is very fast | ||
5534 | * and works. */ | ||
5535 | /* Mark all the text nodes in between the removed formats as dirty. */ | ||
5536 | while (tnode1) | ||
5537 | { | ||
5538 | tnode1->dirty = EINA_TRUE; | ||
5539 | if (tnode1 == tnode2) | ||
5540 | break; | ||
5541 | tnode1 = | ||
5542 | _NODE_TEXT(EINA_INLIST_GET(tnode1)->next); | ||
5543 | } | ||
5544 | } | ||
5545 | |||
5546 | _evas_textblock_changed(o, obj); | ||
5547 | } | ||
5548 | |||
5549 | EAPI void | ||
5550 | evas_textblock_cursor_paragraph_first(Evas_Textblock_Cursor *cur) | ||
5551 | { | ||
5552 | Evas_Object_Textblock *o; | ||
5553 | if (!cur) return; | ||
5554 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
5555 | cur->node = o->text_nodes; | ||
5556 | cur->pos = 0; | ||
5557 | |||
5558 | } | ||
5559 | |||
5560 | EAPI void | ||
5561 | evas_textblock_cursor_paragraph_last(Evas_Textblock_Cursor *cur) | ||
5562 | { | ||
5563 | Evas_Object_Textblock *o; | ||
5564 | Evas_Object_Textblock_Node_Text *node; | ||
5565 | |||
5566 | if (!cur) return; | ||
5567 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
5568 | node = o->text_nodes; | ||
5569 | if (node) | ||
5570 | { | ||
5571 | node = _NODE_TEXT(EINA_INLIST_GET(node)->last); | ||
5572 | cur->node = node; | ||
5573 | cur->pos = 0; | ||
5574 | |||
5575 | evas_textblock_cursor_paragraph_char_last(cur); | ||
5576 | } | ||
5577 | else | ||
5578 | { | ||
5579 | cur->node = NULL; | ||
5580 | cur->pos = 0; | ||
5581 | |||
5582 | } | ||
5583 | } | ||
5584 | |||
5585 | EAPI Eina_Bool | ||
5586 | evas_textblock_cursor_paragraph_next(Evas_Textblock_Cursor *cur) | ||
5587 | { | ||
5588 | if (!cur) return EINA_FALSE; | ||
5589 | if (!cur->node) return EINA_FALSE; | ||
5590 | /* If there is a current text node, return the next text node (if exists) | ||
5591 | * otherwise, just return False. */ | ||
5592 | if (cur->node) | ||
5593 | { | ||
5594 | Evas_Object_Textblock_Node_Text *nnode; | ||
5595 | nnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->next); | ||
5596 | if (nnode) | ||
5597 | { | ||
5598 | cur->node = nnode; | ||
5599 | cur->pos = 0; | ||
5600 | |||
5601 | return EINA_TRUE; | ||
5602 | } | ||
5603 | } | ||
5604 | return EINA_FALSE; | ||
5605 | } | ||
5606 | |||
5607 | EAPI Eina_Bool | ||
5608 | evas_textblock_cursor_paragraph_prev(Evas_Textblock_Cursor *cur) | ||
5609 | { | ||
5610 | Evas_Object_Textblock_Node_Text *node; | ||
5611 | if (!cur) return EINA_FALSE; | ||
5612 | if (!cur->node) return EINA_FALSE; | ||
5613 | /* If the current node is a text node, just get the prev if any, | ||
5614 | * if it's a format, get the current text node out of the format and return | ||
5615 | * the prev text node if any. */ | ||
5616 | node = cur->node; | ||
5617 | /* If there is a current text node, return the prev text node | ||
5618 | * (if exists) otherwise, just return False. */ | ||
5619 | if (node) | ||
5620 | { | ||
5621 | Evas_Object_Textblock_Node_Text *pnode; | ||
5622 | pnode = _NODE_TEXT(EINA_INLIST_GET(cur->node)->prev); | ||
5623 | if (pnode) | ||
5624 | { | ||
5625 | cur->node = pnode; | ||
5626 | evas_textblock_cursor_paragraph_char_last(cur); | ||
5627 | return EINA_TRUE; | ||
5628 | } | ||
5629 | } | ||
5630 | return EINA_FALSE; | ||
5631 | } | ||
5632 | |||
5633 | EAPI void | ||
5634 | evas_textblock_cursor_set_at_format(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *n) | ||
5635 | { | ||
5636 | evas_textblock_cursor_at_format_set(cur, n); | ||
5637 | } | ||
5638 | |||
5639 | EAPI Eina_Bool | ||
5640 | evas_textblock_cursor_format_next(Evas_Textblock_Cursor *cur) | ||
5641 | { | ||
5642 | Evas_Object_Textblock_Node_Format *node; | ||
5643 | |||
5644 | if (!cur) return EINA_FALSE; | ||
5645 | if (!cur->node) return EINA_FALSE; | ||
5646 | /* If the current node is a format node, just get the next if any, | ||
5647 | * if it's a text, get the current format node out of the text and return | ||
5648 | * the next format node if any. */ | ||
5649 | node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); | ||
5650 | node = _evas_textblock_node_format_last_at_off(node); | ||
5651 | if (!node) | ||
5652 | { | ||
5653 | if (cur->node->format_node) | ||
5654 | { | ||
5655 | cur->pos = _evas_textblock_node_format_pos_get(node); | ||
5656 | return EINA_TRUE; | ||
5657 | } | ||
5658 | } | ||
5659 | /* If there is a current text node, return the next format node (if exists) | ||
5660 | * otherwise, just return False. */ | ||
5661 | else | ||
5662 | { | ||
5663 | Evas_Object_Textblock_Node_Format *nnode; | ||
5664 | nnode = _NODE_FORMAT(EINA_INLIST_GET(node)->next); | ||
5665 | if (nnode) | ||
5666 | { | ||
5667 | cur->node = nnode->text_node; | ||
5668 | cur->pos = _evas_textblock_node_format_pos_get(nnode); | ||
5669 | |||
5670 | return EINA_TRUE; | ||
5671 | } | ||
5672 | } | ||
5673 | return EINA_FALSE; | ||
5674 | } | ||
5675 | |||
5676 | EAPI Eina_Bool | ||
5677 | evas_textblock_cursor_format_prev(Evas_Textblock_Cursor *cur) | ||
5678 | { | ||
5679 | const Evas_Object_Textblock_Node_Format *node; | ||
5680 | if (!cur) return EINA_FALSE; | ||
5681 | if (!cur->node) return EINA_FALSE; | ||
5682 | node = evas_textblock_cursor_format_get(cur); | ||
5683 | if (!node) | ||
5684 | { | ||
5685 | node = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); | ||
5686 | if (node) | ||
5687 | { | ||
5688 | cur->node = node->text_node; | ||
5689 | cur->pos = _evas_textblock_node_format_pos_get(node); | ||
5690 | |||
5691 | return EINA_TRUE; | ||
5692 | } | ||
5693 | } | ||
5694 | /* If there is a current text node, return the next text node (if exists) | ||
5695 | * otherwise, just return False. */ | ||
5696 | if (node) | ||
5697 | { | ||
5698 | Evas_Object_Textblock_Node_Format *pnode; | ||
5699 | pnode = _NODE_FORMAT(EINA_INLIST_GET(node)->prev); | ||
5700 | if (pnode) | ||
5701 | { | ||
5702 | cur->node = pnode->text_node; | ||
5703 | cur->pos = _evas_textblock_node_format_pos_get(pnode); | ||
5704 | |||
5705 | return EINA_TRUE; | ||
5706 | } | ||
5707 | } | ||
5708 | return EINA_FALSE; | ||
5709 | } | ||
5710 | |||
5711 | EAPI Eina_Bool | ||
5712 | evas_textblock_cursor_char_next(Evas_Textblock_Cursor *cur) | ||
5713 | { | ||
5714 | int ind; | ||
5715 | const Eina_Unicode *text; | ||
5716 | |||
5717 | if (!cur) return EINA_FALSE; | ||
5718 | if (!cur->node) return EINA_FALSE; | ||
5719 | |||
5720 | ind = cur->pos; | ||
5721 | text = eina_ustrbuf_string_get(cur->node->unicode); | ||
5722 | if (text[ind]) ind++; | ||
5723 | /* Only allow pointing a null if it's the last paragraph. | ||
5724 | * because we don't have a PS there. */ | ||
5725 | if (text[ind]) | ||
5726 | { | ||
5727 | cur->pos = ind; | ||
5728 | return EINA_TRUE; | ||
5729 | } | ||
5730 | else | ||
5731 | { | ||
5732 | if (!evas_textblock_cursor_paragraph_next(cur)) | ||
5733 | { | ||
5734 | /* If we already were at the end, that means we don't have | ||
5735 | * where to go next we should return FALSE */ | ||
5736 | if (cur->pos == (size_t) ind) | ||
5737 | return EINA_FALSE; | ||
5738 | |||
5739 | cur->pos = ind; | ||
5740 | return EINA_TRUE; | ||
5741 | } | ||
5742 | else | ||
5743 | { | ||
5744 | return EINA_TRUE; | ||
5745 | } | ||
5746 | } | ||
5747 | } | ||
5748 | |||
5749 | EAPI Eina_Bool | ||
5750 | evas_textblock_cursor_char_prev(Evas_Textblock_Cursor *cur) | ||
5751 | { | ||
5752 | if (!cur) return EINA_FALSE; | ||
5753 | if (!cur->node) return EINA_FALSE; | ||
5754 | |||
5755 | if (cur->pos != 0) | ||
5756 | { | ||
5757 | cur->pos--; | ||
5758 | return EINA_TRUE; | ||
5759 | } | ||
5760 | return evas_textblock_cursor_paragraph_prev(cur); | ||
5761 | } | ||
5762 | |||
5763 | EAPI void | ||
5764 | evas_textblock_cursor_paragraph_char_first(Evas_Textblock_Cursor *cur) | ||
5765 | { | ||
5766 | if (!cur) return; | ||
5767 | cur->pos = 0; | ||
5768 | |||
5769 | } | ||
5770 | |||
5771 | EAPI void | ||
5772 | evas_textblock_cursor_paragraph_char_last(Evas_Textblock_Cursor *cur) | ||
5773 | { | ||
5774 | int ind; | ||
5775 | |||
5776 | if (!cur) return; | ||
5777 | if (!cur->node) return; | ||
5778 | ind = eina_ustrbuf_length_get(cur->node->unicode); | ||
5779 | /* If it's not the last paragraph, go back one, because we want to point | ||
5780 | * to the PS, not the NULL */ | ||
5781 | if (EINA_INLIST_GET(cur->node)->next) | ||
5782 | ind--; | ||
5783 | |||
5784 | if (ind >= 0) | ||
5785 | cur->pos = ind; | ||
5786 | else | ||
5787 | cur->pos = 0; | ||
5788 | |||
5789 | } | ||
5790 | |||
5791 | EAPI void | ||
5792 | evas_textblock_cursor_line_char_first(Evas_Textblock_Cursor *cur) | ||
5793 | { | ||
5794 | Evas_Object_Textblock *o; | ||
5795 | Evas_Object_Textblock_Line *ln = NULL; | ||
5796 | Evas_Object_Textblock_Item *it = NULL; | ||
5797 | |||
5798 | if (!cur) return; | ||
5799 | if (!cur->node) return; | ||
5800 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
5801 | if (!o->formatted.valid) _relayout(cur->obj); | ||
5802 | |||
5803 | _find_layout_item_match(cur, &ln, &it); | ||
5804 | |||
5805 | if (!ln) return; | ||
5806 | if (ln->items) | ||
5807 | { | ||
5808 | Evas_Object_Textblock_Item *i; | ||
5809 | it = ln->items; | ||
5810 | EINA_INLIST_FOREACH(ln->items, i) | ||
5811 | { | ||
5812 | if (it->text_pos > i->text_pos) | ||
5813 | { | ||
5814 | it = i; | ||
5815 | } | ||
5816 | } | ||
5817 | } | ||
5818 | if (it) | ||
5819 | { | ||
5820 | cur->pos = it->text_pos; | ||
5821 | cur->node = it->text_node; | ||
5822 | } | ||
5823 | } | ||
5824 | |||
5825 | EAPI void | ||
5826 | evas_textblock_cursor_line_char_last(Evas_Textblock_Cursor *cur) | ||
5827 | { | ||
5828 | Evas_Object_Textblock *o; | ||
5829 | Evas_Object_Textblock_Line *ln = NULL; | ||
5830 | Evas_Object_Textblock_Item *it = NULL; | ||
5831 | |||
5832 | if (!cur) return; | ||
5833 | if (!cur->node) return; | ||
5834 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
5835 | if (!o->formatted.valid) _relayout(cur->obj); | ||
5836 | |||
5837 | _find_layout_item_match(cur, &ln, &it); | ||
5838 | |||
5839 | if (!ln) return; | ||
5840 | if (ln->items) | ||
5841 | { | ||
5842 | Evas_Object_Textblock_Item *i; | ||
5843 | it = ln->items; | ||
5844 | EINA_INLIST_FOREACH(ln->items, i) | ||
5845 | { | ||
5846 | if (it->text_pos < i->text_pos) | ||
5847 | { | ||
5848 | it = i; | ||
5849 | } | ||
5850 | } | ||
5851 | } | ||
5852 | if (it) | ||
5853 | { | ||
5854 | size_t ind; | ||
5855 | |||
5856 | cur->node = it->text_node; | ||
5857 | cur->pos = it->text_pos; | ||
5858 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
5859 | { | ||
5860 | ind = _ITEM_TEXT(it)->text_props.text_len - 1; | ||
5861 | if (!IS_AT_END(_ITEM_TEXT(it), ind)) ind++; | ||
5862 | cur->pos += ind; | ||
5863 | } | ||
5864 | else if (!EINA_INLIST_GET(ln)->next && !EINA_INLIST_GET(ln->par)->next) | ||
5865 | { | ||
5866 | cur->pos++; | ||
5867 | } | ||
5868 | } | ||
5869 | } | ||
5870 | |||
5871 | /** | ||
5872 | * @internal | ||
5873 | * checks if a format (as a string) is visible/changes format and sets the | ||
5874 | * fnode properties accordingly. | ||
5875 | * | ||
5876 | * @param fnode the format node | ||
5877 | * @param s the string. | ||
5878 | */ | ||
5879 | static void | ||
5880 | _evas_textblock_format_is_visible(Evas_Object_Textblock_Node_Format *fnode, | ||
5881 | const char *s) | ||
5882 | { | ||
5883 | const char *item; | ||
5884 | Eina_Bool is_opener = EINA_TRUE; | ||
5885 | |||
5886 | fnode->visible = fnode->format_change = EINA_FALSE; | ||
5887 | fnode->anchor = ANCHOR_NONE; | ||
5888 | if (!s) return; | ||
5889 | |||
5890 | if (s[0] == '+' || s[0] == '-') | ||
5891 | { | ||
5892 | is_opener = (s[0] == '+'); | ||
5893 | s++; | ||
5894 | fnode->format_change = EINA_TRUE; | ||
5895 | } | ||
5896 | |||
5897 | while ((item = _format_parse(&s))) | ||
5898 | { | ||
5899 | int itlen = s - item; | ||
5900 | /* We care about all of the formats even after a - except for | ||
5901 | * item which we don't care after a - because it's just a standard | ||
5902 | * closing */ | ||
5903 | if ((!strncmp(item, "\n", itlen) || !strncmp(item, "\\n", itlen)) || | ||
5904 | (!strncmp(item, "\t", itlen) || !strncmp(item, "\\t", itlen)) || | ||
5905 | (!strncmp(item, "ps", itlen) && (itlen >= 2)) || | ||
5906 | (!strncmp(item, "item", itlen) && (itlen >= 4) && is_opener)) | ||
5907 | { | ||
5908 | fnode->visible = EINA_TRUE; | ||
5909 | } | ||
5910 | |||
5911 | if (is_opener && !strncmp(item, "a", itlen)) | ||
5912 | { | ||
5913 | fnode->anchor = ANCHOR_A; | ||
5914 | } | ||
5915 | else if (is_opener && !strncmp(item, "item", itlen) && (itlen >= 4)) | ||
5916 | { | ||
5917 | fnode->anchor = ANCHOR_ITEM; | ||
5918 | } | ||
5919 | } | ||
5920 | } | ||
5921 | |||
5922 | /** | ||
5923 | * Sets the cursor to the position of where the fmt points to. | ||
5924 | * | ||
5925 | * @param cur the cursor to update. | ||
5926 | * @param fmt the format to set according to. | ||
5927 | * @return nothing. | ||
5928 | */ | ||
5929 | static void __UNUSED__ | ||
5930 | _evas_textblock_cursor_node_text_at_format(Evas_Textblock_Cursor *cur, Evas_Object_Textblock_Node_Format *fmt) | ||
5931 | { | ||
5932 | Evas_Object_Textblock_Node_Text *text; | ||
5933 | Evas_Object_Textblock_Node_Format *base_format; | ||
5934 | Evas_Object_Textblock_Node_Format *itr; | ||
5935 | size_t position = 0; | ||
5936 | |||
5937 | if (!cur || !fmt) return; | ||
5938 | /* Find the main format node */ | ||
5939 | text = fmt->text_node; | ||
5940 | cur->node = text; | ||
5941 | base_format = text->format_node; | ||
5942 | EINA_INLIST_FOREACH(base_format, itr) | ||
5943 | { | ||
5944 | if (itr == fmt) | ||
5945 | { | ||
5946 | break; | ||
5947 | } | ||
5948 | position += itr->offset; | ||
5949 | } | ||
5950 | cur->pos = position; | ||
5951 | |||
5952 | } | ||
5953 | |||
5954 | |||
5955 | /** | ||
5956 | * @internal | ||
5957 | * Remove pairs of + and - formats and also remove formats without + or - | ||
5958 | * i.e formats that pair to themselves. Only removes invisible formats | ||
5959 | * that pair themselves, if you want to remove invisible formats that pair | ||
5960 | * themselves, please first change fmt->visible to EINA_FALSE. | ||
5961 | * | ||
5962 | * @param o the textblock object. | ||
5963 | * @param fmt the current format. | ||
5964 | */ | ||
5965 | static void | ||
5966 | _evas_textblock_node_format_remove_matching(Evas_Object_Textblock *o, | ||
5967 | Evas_Object_Textblock_Node_Format *fmt) | ||
5968 | { | ||
5969 | Evas_Object_Textblock_Node_Text *tnode; | ||
5970 | Eina_List *formats = NULL; | ||
5971 | size_t offset = 0; | ||
5972 | |||
5973 | if (!fmt) return; | ||
5974 | |||
5975 | tnode = fmt->text_node; | ||
5976 | |||
5977 | do | ||
5978 | { | ||
5979 | Evas_Object_Textblock_Node_Format *nnode; | ||
5980 | const char *fstr = fmt->orig_format; | ||
5981 | |||
5982 | nnode = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next); | ||
5983 | if (nnode) | ||
5984 | { | ||
5985 | offset = nnode->offset; | ||
5986 | } | ||
5987 | |||
5988 | |||
5989 | if (fstr && (*fstr == '+')) | ||
5990 | { | ||
5991 | formats = eina_list_prepend(formats, fmt); | ||
5992 | } | ||
5993 | else if (fstr && (*fstr == '-')) | ||
5994 | { | ||
5995 | Evas_Object_Textblock_Node_Format *fnode; | ||
5996 | size_t fstr_len; | ||
5997 | /* Skip the '-' */ | ||
5998 | fstr++; | ||
5999 | fstr_len = strlen(fstr); | ||
6000 | /* Generic popper, just pop */ | ||
6001 | if (((fstr[0] == ' ') && !fstr[1]) || !fstr[0]) | ||
6002 | { | ||
6003 | fnode = eina_list_data_get(formats); | ||
6004 | formats = eina_list_remove_list(formats, formats); | ||
6005 | _evas_textblock_node_format_remove(o, fnode, 0); | ||
6006 | _evas_textblock_node_format_remove(o, fmt, 0); | ||
6007 | } | ||
6008 | /* Find the matching format and pop it, if the matching format | ||
6009 | * is our format, i.e the last one, pop and break. */ | ||
6010 | else | ||
6011 | { | ||
6012 | Eina_List *i, *next; | ||
6013 | EINA_LIST_FOREACH_SAFE(formats, i, next, fnode) | ||
6014 | { | ||
6015 | if (_FORMAT_IS_CLOSER_OF( | ||
6016 | fnode->orig_format, fstr, fstr_len)) | ||
6017 | { | ||
6018 | fnode = eina_list_data_get(i); | ||
6019 | formats = eina_list_remove_list(formats, i); | ||
6020 | _evas_textblock_node_format_remove(o, fnode, 0); | ||
6021 | _evas_textblock_node_format_remove(o, fmt, 0); | ||
6022 | break; | ||
6023 | } | ||
6024 | } | ||
6025 | } | ||
6026 | } | ||
6027 | else if (!fmt->visible) | ||
6028 | { | ||
6029 | _evas_textblock_node_format_remove(o, fmt, 0); | ||
6030 | } | ||
6031 | fmt = nnode; | ||
6032 | } | ||
6033 | while (fmt && (offset == 0) && (fmt->text_node == tnode)); | ||
6034 | eina_list_free(formats); | ||
6035 | } | ||
6036 | /** | ||
6037 | * @internal | ||
6038 | * Add the offset (may be negative) to the first node after fmt which is | ||
6039 | * pointing to the text node tnode or to o->format_nodes if fmt is null | ||
6040 | * and it points to tnode. | ||
6041 | * | ||
6042 | * @param o the textblock object. | ||
6043 | * @param tnode the text node the format should point to. | ||
6044 | * @param fmt the current format. | ||
6045 | * @param offset the offest to add (may be negative). | ||
6046 | */ | ||
6047 | static void | ||
6048 | _evas_textblock_node_format_adjust_offset(Evas_Object_Textblock *o, | ||
6049 | Evas_Object_Textblock_Node_Text *tnode, | ||
6050 | Evas_Object_Textblock_Node_Format *fmt, int offset) | ||
6051 | { | ||
6052 | if (fmt) | ||
6053 | { | ||
6054 | fmt = _NODE_FORMAT(EINA_INLIST_GET(fmt)->next); | ||
6055 | } | ||
6056 | else | ||
6057 | { | ||
6058 | fmt = o->format_nodes; | ||
6059 | } | ||
6060 | if (fmt && (tnode == fmt->text_node)) | ||
6061 | { | ||
6062 | fmt->offset += offset; | ||
6063 | } | ||
6064 | } | ||
6065 | |||
6066 | /** | ||
6067 | * @internal | ||
6068 | * Removes a format node updating the offset of the next format node and the | ||
6069 | * text nodes pointing to this node. | ||
6070 | * | ||
6071 | * @param o the textblock object. | ||
6072 | * @param n the fromat node to remove | ||
6073 | */ | ||
6074 | static void | ||
6075 | _evas_textblock_node_format_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Format *n, int visible_adjustment) | ||
6076 | { | ||
6077 | /* Update the text nodes about the change */ | ||
6078 | { | ||
6079 | Evas_Object_Textblock_Node_Format *nnode; | ||
6080 | nnode = _NODE_FORMAT(EINA_INLIST_GET(n)->next); | ||
6081 | /* If there's a next node that belongs to the same text node | ||
6082 | * and the curret node was the main one, advance the format node */ | ||
6083 | if (nnode && (nnode->text_node == n->text_node)) | ||
6084 | { | ||
6085 | if (nnode->text_node->format_node == n) | ||
6086 | { | ||
6087 | nnode->text_node->format_node = nnode; | ||
6088 | } | ||
6089 | } | ||
6090 | else | ||
6091 | { | ||
6092 | Evas_Object_Textblock_Node_Text *tnode; | ||
6093 | /* If there's no next one update the text nodes */ | ||
6094 | nnode = _NODE_FORMAT(EINA_INLIST_GET(n)->prev); | ||
6095 | tnode = n->text_node; | ||
6096 | /* Even if it's not the current text_node's main node | ||
6097 | * it can still be the next's. */ | ||
6098 | if (tnode && (tnode->format_node != n)) | ||
6099 | { | ||
6100 | tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next); | ||
6101 | } | ||
6102 | while (tnode && (tnode->format_node == n)) | ||
6103 | { | ||
6104 | tnode->format_node = nnode; | ||
6105 | tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next); | ||
6106 | } | ||
6107 | } | ||
6108 | } | ||
6109 | _evas_textblock_node_format_adjust_offset(o, n->text_node, n, | ||
6110 | n->offset - visible_adjustment); | ||
6111 | |||
6112 | o->format_nodes = _NODE_FORMAT(eina_inlist_remove( | ||
6113 | EINA_INLIST_GET(o->format_nodes), EINA_INLIST_GET(n))); | ||
6114 | _evas_textblock_node_format_free(o, n); | ||
6115 | } | ||
6116 | |||
6117 | /** | ||
6118 | * @internal | ||
6119 | * Sets all the offsets of the format nodes between start and end in the text | ||
6120 | * node n to 0 and sets visibility to EINA_FALSE. | ||
6121 | * If end == -1 end means the end of the string. | ||
6122 | * Assumes there is a prev node or the current node will be preserved. | ||
6123 | * | ||
6124 | * @param n the text node the positinos refer to. | ||
6125 | * @param start the start of where to delete from. | ||
6126 | * @param end the end of the section to delete, if end == -1 it means the end of the string. | ||
6127 | * @returns #EINA_TRUE if removed a PS, false otherwise. | ||
6128 | */ | ||
6129 | static Eina_Bool | ||
6130 | _evas_textblock_node_text_adjust_offsets_to_start(Evas_Object_Textblock *o, | ||
6131 | Evas_Object_Textblock_Node_Text *n, size_t start, int end) | ||
6132 | { | ||
6133 | Evas_Object_Textblock_Node_Format *last_node, *itr; | ||
6134 | Evas_Object_Textblock_Node_Text *new_node; | ||
6135 | int use_end = 1; | ||
6136 | int delta = 0; | ||
6137 | int first = 1; | ||
6138 | int update_format_node; | ||
6139 | size_t pos = 0; | ||
6140 | int orig_end; | ||
6141 | |||
6142 | itr = n->format_node; | ||
6143 | if (!itr || (itr->text_node != n)) return EINA_FALSE; | ||
6144 | |||
6145 | orig_end = end; | ||
6146 | if ((end < 0) || ((size_t) end == eina_ustrbuf_length_get(n->unicode))) | ||
6147 | { | ||
6148 | use_end = 0; | ||
6149 | } | ||
6150 | else if (end > 0) | ||
6151 | { | ||
6152 | /* We don't want the last one */ | ||
6153 | end--; | ||
6154 | } | ||
6155 | |||
6156 | /* If we are not removing the text node, all should stay in this text | ||
6157 | * node, otherwise, everything should move to the previous node */ | ||
6158 | if ((start == 0) && !use_end) | ||
6159 | { | ||
6160 | new_node = _NODE_TEXT(EINA_INLIST_GET(n)->prev); | ||
6161 | if (!new_node) | ||
6162 | { | ||
6163 | new_node = n; | ||
6164 | } | ||
6165 | } | ||
6166 | else | ||
6167 | { | ||
6168 | new_node = n; | ||
6169 | } | ||
6170 | |||
6171 | /* Find the first node after start */ | ||
6172 | while (itr && (itr->text_node == n)) | ||
6173 | { | ||
6174 | pos += itr->offset; | ||
6175 | if (pos >= start) | ||
6176 | { | ||
6177 | break; | ||
6178 | } | ||
6179 | itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next); | ||
6180 | } | ||
6181 | |||
6182 | if (!itr || (itr->text_node != n)) | ||
6183 | { | ||
6184 | return EINA_FALSE; | ||
6185 | } | ||
6186 | |||
6187 | update_format_node = ((itr == n->format_node) && (new_node != n)); | ||
6188 | delta = orig_end - pos; | ||
6189 | itr->offset -= pos - start; | ||
6190 | |||
6191 | while (itr && (itr->text_node == n)) | ||
6192 | { | ||
6193 | last_node = itr; | ||
6194 | itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next); | ||
6195 | |||
6196 | if (!first) | ||
6197 | { | ||
6198 | pos += last_node->offset; | ||
6199 | } | ||
6200 | |||
6201 | /* start is negative when this gets relevant */ | ||
6202 | if (use_end && (pos > (size_t) end)) | ||
6203 | { | ||
6204 | last_node->offset -= delta; | ||
6205 | break; | ||
6206 | } | ||
6207 | |||
6208 | delta = orig_end - pos; | ||
6209 | if (!first) | ||
6210 | { | ||
6211 | last_node->offset = 0; | ||
6212 | } | ||
6213 | else | ||
6214 | { | ||
6215 | first = 0; | ||
6216 | } | ||
6217 | last_node->visible = EINA_FALSE; | ||
6218 | |||
6219 | if (!itr || (itr && (itr->text_node != n))) | ||
6220 | { | ||
6221 | /* Remove the PS, and return since it's the end of the node */ | ||
6222 | if (_IS_PARAGRAPH_SEPARATOR(o, last_node->format)) | ||
6223 | { | ||
6224 | _evas_textblock_node_format_remove(o, last_node, 0); | ||
6225 | return EINA_TRUE; | ||
6226 | } | ||
6227 | |||
6228 | } | ||
6229 | last_node->text_node = new_node; | ||
6230 | if (update_format_node) | ||
6231 | { | ||
6232 | n->format_node = last_node; | ||
6233 | } | ||
6234 | } | ||
6235 | |||
6236 | return EINA_FALSE; | ||
6237 | } | ||
6238 | |||
6239 | /** | ||
6240 | * @internal | ||
6241 | * Removes all the format nodes between start and end in the text node n. | ||
6242 | * This function updates the offset of the next format node and the | ||
6243 | * text nodes pointing to it. if end == -1 end means the end of the string. | ||
6244 | * | ||
6245 | * @param o the textblock object. | ||
6246 | * @param n the text node the positinos refer to. | ||
6247 | * @param start the start of where to delete from. | ||
6248 | * @param end the end of the section to delete, if end == -1 it means the end of the string. | ||
6249 | */ | ||
6250 | static void | ||
6251 | _evas_textblock_node_text_remove_formats_between(Evas_Object_Textblock *o, | ||
6252 | Evas_Object_Textblock_Node_Text *n, int start, int end) | ||
6253 | { | ||
6254 | Evas_Object_Textblock_Node_Format *itr; | ||
6255 | int use_end = 1; | ||
6256 | int offset = end - start; | ||
6257 | itr = n->format_node; | ||
6258 | |||
6259 | if (itr) | ||
6260 | start -= itr->offset; | ||
6261 | if (offset < 0) offset = 0; | ||
6262 | if (end < 0) use_end = 0; | ||
6263 | while (itr && (itr->text_node == n)) | ||
6264 | { | ||
6265 | Evas_Object_Textblock_Node_Format *nnode; | ||
6266 | int tmp_offset = 0; | ||
6267 | |||
6268 | /* start is negative when this gets relevant */ | ||
6269 | if ((offset + start < 0) && use_end) | ||
6270 | { | ||
6271 | break; | ||
6272 | } | ||
6273 | nnode = _NODE_FORMAT(EINA_INLIST_GET(itr)->next); | ||
6274 | if (nnode) | ||
6275 | { | ||
6276 | tmp_offset = nnode->offset; | ||
6277 | } | ||
6278 | if (start <= 0) | ||
6279 | { | ||
6280 | /* Don't do visible adjustments because we are removing the visual | ||
6281 | * chars anyway and taking those into account */ | ||
6282 | _evas_textblock_node_format_remove(o, itr, 0); | ||
6283 | } | ||
6284 | start -= tmp_offset; | ||
6285 | itr = nnode; | ||
6286 | } | ||
6287 | } | ||
6288 | |||
6289 | /** | ||
6290 | * @internal | ||
6291 | * Returns the first format in the range between start and end in the textblock | ||
6292 | * n. | ||
6293 | * | ||
6294 | * @param o the textblock object. | ||
6295 | * @param n the text node the positinos refer to. | ||
6296 | * @param start the start of where to delete from. | ||
6297 | * @param end the end of the section to delete, if end == -1 it means the end of the string. | ||
6298 | */ | ||
6299 | static Evas_Object_Textblock_Node_Format * | ||
6300 | _evas_textblock_node_text_get_first_format_between( | ||
6301 | Evas_Object_Textblock_Node_Text *n, int start, int end) | ||
6302 | { | ||
6303 | Evas_Object_Textblock_Node_Format *itr; | ||
6304 | int use_end = 1; | ||
6305 | itr = n->format_node; | ||
6306 | if (end < 0) use_end = 0; | ||
6307 | while (itr && (itr->text_node == n)) | ||
6308 | { | ||
6309 | start -= itr->offset; | ||
6310 | end -= itr->offset; | ||
6311 | if ((end <= 0) && use_end) | ||
6312 | { | ||
6313 | break; | ||
6314 | } | ||
6315 | if (start <= 0) | ||
6316 | { | ||
6317 | return itr; | ||
6318 | } | ||
6319 | itr = _NODE_FORMAT(EINA_INLIST_GET(itr)->next); | ||
6320 | } | ||
6321 | return NULL; | ||
6322 | } | ||
6323 | |||
6324 | /** | ||
6325 | * Removes a text node and the corresponding format nodes. | ||
6326 | * | ||
6327 | * @param o the textblock objec.t | ||
6328 | * @param n the node to remove. | ||
6329 | */ | ||
6330 | static void | ||
6331 | _evas_textblock_node_text_remove(Evas_Object_Textblock *o, Evas_Object_Textblock_Node_Text *n) | ||
6332 | { | ||
6333 | _evas_textblock_node_text_adjust_offsets_to_start(o, n, 0, -1); | ||
6334 | |||
6335 | o->text_nodes = _NODE_TEXT(eina_inlist_remove( | ||
6336 | EINA_INLIST_GET(o->text_nodes), EINA_INLIST_GET(n))); | ||
6337 | _evas_textblock_node_text_free(n); | ||
6338 | } | ||
6339 | |||
6340 | /** | ||
6341 | * @internal | ||
6342 | * Return the position where the formats starts at. | ||
6343 | * | ||
6344 | * @param fmt the format to return the position of. | ||
6345 | * @return the position of the format in the text node it points to. | ||
6346 | */ | ||
6347 | static size_t | ||
6348 | _evas_textblock_node_format_pos_get(const Evas_Object_Textblock_Node_Format *fmt) | ||
6349 | { | ||
6350 | Evas_Object_Textblock_Node_Text *text; | ||
6351 | Evas_Object_Textblock_Node_Format *base_format; | ||
6352 | Evas_Object_Textblock_Node_Format *itr; | ||
6353 | size_t position = 0; | ||
6354 | |||
6355 | if (!fmt) return 0; | ||
6356 | /* Find the main format node */ | ||
6357 | text = fmt->text_node; | ||
6358 | base_format = text->format_node; | ||
6359 | EINA_INLIST_FOREACH(base_format, itr) | ||
6360 | { | ||
6361 | if (itr == fmt) | ||
6362 | { | ||
6363 | break; | ||
6364 | } | ||
6365 | position += itr->offset; | ||
6366 | } | ||
6367 | return position + fmt->offset; | ||
6368 | } | ||
6369 | |||
6370 | EAPI int | ||
6371 | evas_textblock_cursor_pos_get(const Evas_Textblock_Cursor *cur) | ||
6372 | { | ||
6373 | Evas_Object_Textblock *o; | ||
6374 | Evas_Object_Textblock_Node_Text *n; | ||
6375 | size_t npos = 0; | ||
6376 | |||
6377 | if (!cur) return -1; | ||
6378 | if (!cur->node) return 0; | ||
6379 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
6380 | n = o->text_nodes; | ||
6381 | while (n != cur->node) | ||
6382 | { | ||
6383 | npos += eina_ustrbuf_length_get(n->unicode); | ||
6384 | n = _NODE_TEXT(EINA_INLIST_GET(n)->next); | ||
6385 | } | ||
6386 | return npos + cur->pos; | ||
6387 | } | ||
6388 | |||
6389 | EAPI void | ||
6390 | evas_textblock_cursor_pos_set(Evas_Textblock_Cursor *cur, int _pos) | ||
6391 | { | ||
6392 | Evas_Object_Textblock *o; | ||
6393 | Evas_Object_Textblock_Node_Text *n; | ||
6394 | size_t pos; | ||
6395 | |||
6396 | if (!cur) return; | ||
6397 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
6398 | |||
6399 | if (_pos < 0) | ||
6400 | { | ||
6401 | pos = 0; | ||
6402 | } | ||
6403 | else | ||
6404 | { | ||
6405 | pos = (size_t) _pos; | ||
6406 | } | ||
6407 | |||
6408 | n = o->text_nodes; | ||
6409 | while (n && (pos >= eina_ustrbuf_length_get(n->unicode))) | ||
6410 | { | ||
6411 | pos -= eina_ustrbuf_length_get(n->unicode); | ||
6412 | n = _NODE_TEXT(EINA_INLIST_GET(n)->next); | ||
6413 | } | ||
6414 | |||
6415 | if (n) | ||
6416 | { | ||
6417 | cur->node = n; | ||
6418 | cur->pos = pos; | ||
6419 | } | ||
6420 | else if (o->text_nodes) | ||
6421 | { | ||
6422 | /* In case we went pass the last node, we need to put the cursor | ||
6423 | * at the absolute end. */ | ||
6424 | Evas_Object_Textblock_Node_Text *last_n; | ||
6425 | |||
6426 | last_n = _NODE_TEXT(EINA_INLIST_GET(o->text_nodes)->last); | ||
6427 | pos = eina_ustrbuf_length_get(last_n->unicode); | ||
6428 | |||
6429 | cur->node = last_n; | ||
6430 | cur->pos = pos; | ||
6431 | } | ||
6432 | |||
6433 | } | ||
6434 | |||
6435 | EAPI Eina_Bool | ||
6436 | evas_textblock_cursor_line_set(Evas_Textblock_Cursor *cur, int line) | ||
6437 | { | ||
6438 | Evas_Object_Textblock *o; | ||
6439 | Evas_Object_Textblock_Line *ln; | ||
6440 | Evas_Object_Textblock_Item *it; | ||
6441 | |||
6442 | if (!cur) return EINA_FALSE; | ||
6443 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
6444 | if (!o->formatted.valid) _relayout(cur->obj); | ||
6445 | |||
6446 | ln = _find_layout_line_num(cur->obj, line); | ||
6447 | if (!ln) return EINA_FALSE; | ||
6448 | it = (Evas_Object_Textblock_Item *)ln->items; | ||
6449 | if (it) | ||
6450 | { | ||
6451 | cur->pos = it->text_pos; | ||
6452 | cur->node = it->text_node; | ||
6453 | } | ||
6454 | else | ||
6455 | { | ||
6456 | cur->pos = 0; | ||
6457 | |||
6458 | cur->node = o->text_nodes; | ||
6459 | } | ||
6460 | return EINA_TRUE; | ||
6461 | } | ||
6462 | |||
6463 | EAPI int | ||
6464 | evas_textblock_cursor_compare(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) | ||
6465 | { | ||
6466 | Eina_Inlist *l1, *l2; | ||
6467 | |||
6468 | if (!cur1) return 0; | ||
6469 | if (!cur2) return 0; | ||
6470 | if (cur1->obj != cur2->obj) return 0; | ||
6471 | if ((!cur1->node) || (!cur2->node)) return 0; | ||
6472 | if (cur1->node == cur2->node) | ||
6473 | { | ||
6474 | if (cur1->pos < cur2->pos) return -1; /* cur1 < cur2 */ | ||
6475 | else if (cur1->pos > cur2->pos) return 1; /* cur2 < cur1 */ | ||
6476 | return 0; | ||
6477 | } | ||
6478 | for (l1 = EINA_INLIST_GET(cur1->node), | ||
6479 | l2 = EINA_INLIST_GET(cur1->node); (l1) || (l2);) | ||
6480 | { | ||
6481 | if (l1 == EINA_INLIST_GET(cur2->node)) return 1; /* cur2 < cur 1 */ | ||
6482 | else if (l2 == EINA_INLIST_GET(cur2->node)) return -1; /* cur1 < cur 2 */ | ||
6483 | else if (!l1) return -1; /* cur1 < cur 2 */ | ||
6484 | else if (!l2) return 1; /* cur2 < cur 1 */ | ||
6485 | l1 = l1->prev; | ||
6486 | l2 = l2->next; | ||
6487 | } | ||
6488 | return 0; | ||
6489 | } | ||
6490 | |||
6491 | EAPI void | ||
6492 | evas_textblock_cursor_copy(const Evas_Textblock_Cursor *cur, Evas_Textblock_Cursor *cur_dest) | ||
6493 | { | ||
6494 | if (!cur) return; | ||
6495 | if (!cur_dest) return; | ||
6496 | if (cur->obj != cur_dest->obj) return; | ||
6497 | cur_dest->pos = cur->pos; | ||
6498 | cur_dest->node = cur->node; | ||
6499 | |||
6500 | } | ||
6501 | |||
6502 | |||
6503 | /* text controls */ | ||
6504 | /** | ||
6505 | * @internal | ||
6506 | * Free a text node. Shouldn't be used usually, it's better to use | ||
6507 | * @ref _evas_textblock_node_text_remove for most cases . | ||
6508 | * | ||
6509 | * @param n the text node to free | ||
6510 | * @see _evas_textblock_node_text_remove | ||
6511 | */ | ||
6512 | static void | ||
6513 | _evas_textblock_node_text_free(Evas_Object_Textblock_Node_Text *n) | ||
6514 | { | ||
6515 | if (!n) return; | ||
6516 | eina_ustrbuf_free(n->unicode); | ||
6517 | if (n->utf8) | ||
6518 | free(n->utf8); | ||
6519 | if (n->par) | ||
6520 | n->par->text_node = NULL; | ||
6521 | free(n); | ||
6522 | } | ||
6523 | |||
6524 | /** | ||
6525 | * @internal | ||
6526 | * Create a new text node | ||
6527 | * | ||
6528 | * @return the new text node. | ||
6529 | */ | ||
6530 | static Evas_Object_Textblock_Node_Text * | ||
6531 | _evas_textblock_node_text_new(void) | ||
6532 | { | ||
6533 | Evas_Object_Textblock_Node_Text *n; | ||
6534 | |||
6535 | n = calloc(1, sizeof(Evas_Object_Textblock_Node_Text)); | ||
6536 | n->unicode = eina_ustrbuf_new(); | ||
6537 | /* We want to layout each paragraph at least once. */ | ||
6538 | n->dirty = EINA_TRUE; | ||
6539 | n->is_new = EINA_TRUE; | ||
6540 | |||
6541 | return n; | ||
6542 | } | ||
6543 | |||
6544 | /** | ||
6545 | * @internal | ||
6546 | * Break a paragraph. This does not add a PS but only splits the paragraph | ||
6547 | * where a ps was just added! | ||
6548 | * | ||
6549 | * @param cur the cursor to break at. | ||
6550 | * @param fnode the format node of the PS just added. | ||
6551 | * @return Returns no value. | ||
6552 | */ | ||
6553 | static void | ||
6554 | _evas_textblock_cursor_break_paragraph(Evas_Textblock_Cursor *cur, | ||
6555 | Evas_Object_Textblock_Node_Format *fnode) | ||
6556 | { | ||
6557 | Evas_Object_Textblock *o; | ||
6558 | Evas_Object_Textblock_Node_Text *n; | ||
6559 | |||
6560 | if (!cur) return; | ||
6561 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
6562 | |||
6563 | n = _evas_textblock_node_text_new(); | ||
6564 | o->text_nodes = _NODE_TEXT(eina_inlist_append_relative( | ||
6565 | EINA_INLIST_GET(o->text_nodes), | ||
6566 | EINA_INLIST_GET(n), | ||
6567 | EINA_INLIST_GET(cur->node))); | ||
6568 | /* Handle text and format changes. */ | ||
6569 | if (cur->node) | ||
6570 | { | ||
6571 | Evas_Object_Textblock_Node_Format *nnode; | ||
6572 | size_t len, start; | ||
6573 | const Eina_Unicode *text; | ||
6574 | |||
6575 | /* If there was a format node in the delete range, | ||
6576 | * make it our format and update the text_node fields, | ||
6577 | * otherwise, use the paragraph separator | ||
6578 | * of the previous paragraph. */ | ||
6579 | nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
6580 | if (nnode && (nnode->text_node == cur->node)) | ||
6581 | { | ||
6582 | n->format_node = nnode; | ||
6583 | nnode->offset--; /* We don't have to take the replacement char | ||
6584 | into account anymore */ | ||
6585 | while (nnode && (nnode->text_node == cur->node)) | ||
6586 | { | ||
6587 | nnode->text_node = n; | ||
6588 | nnode = _NODE_FORMAT(EINA_INLIST_GET(nnode)->next); | ||
6589 | } | ||
6590 | } | ||
6591 | else | ||
6592 | { | ||
6593 | n->format_node = fnode; | ||
6594 | } | ||
6595 | |||
6596 | /* cur->pos now points to the PS, move after. */ | ||
6597 | start = cur->pos + 1; | ||
6598 | len = eina_ustrbuf_length_get(cur->node->unicode) - start; | ||
6599 | if (len > 0) | ||
6600 | { | ||
6601 | text = eina_ustrbuf_string_get(cur->node->unicode); | ||
6602 | eina_ustrbuf_append_length(n->unicode, text + start, len); | ||
6603 | eina_ustrbuf_remove(cur->node->unicode, start, start + len); | ||
6604 | cur->node->dirty = EINA_TRUE; | ||
6605 | } | ||
6606 | } | ||
6607 | else | ||
6608 | { | ||
6609 | fnode = o->format_nodes; | ||
6610 | if (fnode) | ||
6611 | { | ||
6612 | fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->last); | ||
6613 | } | ||
6614 | n->format_node = fnode; | ||
6615 | } | ||
6616 | } | ||
6617 | |||
6618 | /** | ||
6619 | * @internal | ||
6620 | * Set the node and offset of all the curs after cur. | ||
6621 | * | ||
6622 | * @param cur the cursor. | ||
6623 | * @param n the current textblock node. | ||
6624 | * @param new_node the new node to set. | ||
6625 | */ | ||
6626 | static void | ||
6627 | _evas_textblock_cursors_set_node(Evas_Object_Textblock *o, | ||
6628 | const Evas_Object_Textblock_Node_Text *n, | ||
6629 | Evas_Object_Textblock_Node_Text *new_node) | ||
6630 | { | ||
6631 | Eina_List *l; | ||
6632 | Evas_Textblock_Cursor *data; | ||
6633 | |||
6634 | if (n == o->cursor->node) | ||
6635 | { | ||
6636 | o->cursor->pos = 0; | ||
6637 | o->cursor->node = new_node; | ||
6638 | } | ||
6639 | EINA_LIST_FOREACH(o->cursors, l, data) | ||
6640 | { | ||
6641 | if (n == data->node) | ||
6642 | { | ||
6643 | data->pos = 0; | ||
6644 | data->node = new_node; | ||
6645 | } | ||
6646 | } | ||
6647 | } | ||
6648 | |||
6649 | /** | ||
6650 | * @internal | ||
6651 | * Update the offset of all the cursors after cur. | ||
6652 | * | ||
6653 | * @param cur the cursor. | ||
6654 | * @param n the current textblock node. | ||
6655 | * @param start the starting pos. | ||
6656 | * @param offset how much to adjust (can be negative). | ||
6657 | */ | ||
6658 | static void | ||
6659 | _evas_textblock_cursors_update_offset(const Evas_Textblock_Cursor *cur, | ||
6660 | const Evas_Object_Textblock_Node_Text *n, | ||
6661 | size_t start, int offset) | ||
6662 | { | ||
6663 | Eina_List *l; | ||
6664 | Evas_Textblock_Cursor *data; | ||
6665 | Evas_Object_Textblock *o; | ||
6666 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
6667 | |||
6668 | if (cur != o->cursor) | ||
6669 | { | ||
6670 | if ((n == o->cursor->node) && | ||
6671 | (o->cursor->pos > start)) | ||
6672 | { | ||
6673 | if ((offset < 0) && (o->cursor->pos <= (size_t) (-1 * offset))) | ||
6674 | { | ||
6675 | o->cursor->pos = 0; | ||
6676 | } | ||
6677 | else | ||
6678 | { | ||
6679 | o->cursor->pos += offset; | ||
6680 | } | ||
6681 | } | ||
6682 | } | ||
6683 | EINA_LIST_FOREACH(o->cursors, l, data) | ||
6684 | { | ||
6685 | if (data != cur) | ||
6686 | { | ||
6687 | if ((n == data->node) && | ||
6688 | (data->pos > start)) | ||
6689 | { | ||
6690 | if ((offset < 0) && (data->pos <= (size_t) (-1 * offset))) | ||
6691 | { | ||
6692 | data->pos = 0; | ||
6693 | } | ||
6694 | else | ||
6695 | { | ||
6696 | data->pos += offset; | ||
6697 | } | ||
6698 | } | ||
6699 | else if (!data->node) | ||
6700 | { | ||
6701 | data->node = o->text_nodes; | ||
6702 | data->pos = 0; | ||
6703 | } | ||
6704 | } | ||
6705 | } | ||
6706 | } | ||
6707 | |||
6708 | /** | ||
6709 | * @internal | ||
6710 | * Mark that the textblock has changed. | ||
6711 | * | ||
6712 | * @param o the textblock object. | ||
6713 | * @param obj the evas object. | ||
6714 | */ | ||
6715 | static void | ||
6716 | _evas_textblock_changed(Evas_Object_Textblock *o, Evas_Object *obj) | ||
6717 | { | ||
6718 | o->formatted.valid = 0; | ||
6719 | o->native.valid = 0; | ||
6720 | o->content_changed = 1; | ||
6721 | if (o->markup_text) | ||
6722 | { | ||
6723 | free(o->markup_text); | ||
6724 | o->markup_text = NULL; | ||
6725 | } | ||
6726 | |||
6727 | evas_object_change(obj); | ||
6728 | } | ||
6729 | |||
6730 | static void | ||
6731 | _evas_textblock_invalidate_all(Evas_Object_Textblock *o) | ||
6732 | { | ||
6733 | Evas_Object_Textblock_Node_Text *n; | ||
6734 | |||
6735 | EINA_INLIST_FOREACH(o->text_nodes, n) | ||
6736 | { | ||
6737 | n->dirty = EINA_TRUE; | ||
6738 | } | ||
6739 | } | ||
6740 | |||
6741 | EAPI int | ||
6742 | evas_textblock_cursor_text_append(Evas_Textblock_Cursor *cur, const char *_text) | ||
6743 | { | ||
6744 | Evas_Object_Textblock *o; | ||
6745 | Evas_Object_Textblock_Node_Text *n; | ||
6746 | Evas_Object_Textblock_Node_Format *fnode = NULL; | ||
6747 | Eina_Unicode *text; | ||
6748 | int len = 0; | ||
6749 | |||
6750 | if (!cur) return 0; | ||
6751 | text = eina_unicode_utf8_to_unicode(_text, &len); | ||
6752 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
6753 | |||
6754 | n = cur->node; | ||
6755 | if (n) | ||
6756 | { | ||
6757 | Evas_Object_Textblock_Node_Format *nnode; | ||
6758 | fnode = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); | ||
6759 | fnode = _evas_textblock_node_format_last_at_off(fnode); | ||
6760 | /* find the node after the current in the same paragraph | ||
6761 | * either we find one and then take the next, or we try to get | ||
6762 | * the first for the paragraph which must be after our position */ | ||
6763 | if (fnode) | ||
6764 | { | ||
6765 | if (!evas_textblock_cursor_format_is_visible_get(cur)) | ||
6766 | { | ||
6767 | nnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
6768 | if (nnode && (nnode->text_node == n)) | ||
6769 | { | ||
6770 | fnode = nnode; | ||
6771 | } | ||
6772 | else | ||
6773 | { | ||
6774 | fnode = NULL; | ||
6775 | } | ||
6776 | } | ||
6777 | } | ||
6778 | else | ||
6779 | { | ||
6780 | fnode = n->format_node; | ||
6781 | } | ||
6782 | } | ||
6783 | else if (o->text_nodes) | ||
6784 | { | ||
6785 | n = cur->node = o->text_nodes; | ||
6786 | cur->pos = 0; | ||
6787 | } | ||
6788 | else | ||
6789 | { | ||
6790 | n = _evas_textblock_node_text_new(); | ||
6791 | o->text_nodes = _NODE_TEXT(eina_inlist_append( | ||
6792 | EINA_INLIST_GET(o->text_nodes), | ||
6793 | EINA_INLIST_GET(n))); | ||
6794 | cur->node = n; | ||
6795 | } | ||
6796 | |||
6797 | eina_ustrbuf_insert_length(n->unicode, text, len, cur->pos); | ||
6798 | /* Advance the formats */ | ||
6799 | if (fnode && (fnode->text_node == cur->node)) | ||
6800 | fnode->offset += len; | ||
6801 | |||
6802 | /* Update all the cursors after our position. */ | ||
6803 | _evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, len); | ||
6804 | |||
6805 | _evas_textblock_changed(o, cur->obj); | ||
6806 | n->dirty = EINA_TRUE; | ||
6807 | free(text); | ||
6808 | |||
6809 | if (!o->cursor->node) | ||
6810 | o->cursor->node = o->text_nodes; | ||
6811 | return len; | ||
6812 | } | ||
6813 | |||
6814 | EAPI int | ||
6815 | evas_textblock_cursor_text_prepend(Evas_Textblock_Cursor *cur, const char *_text) | ||
6816 | { | ||
6817 | int len; | ||
6818 | /*append is essentially prepend without advancing */ | ||
6819 | len = evas_textblock_cursor_text_append(cur, _text); | ||
6820 | cur->pos += len; /*Advance */ | ||
6821 | return len; | ||
6822 | } | ||
6823 | |||
6824 | /** | ||
6825 | * @internal | ||
6826 | * Free a format node | ||
6827 | * | ||
6828 | * @param o the textblock object | ||
6829 | * @param n the format node to free | ||
6830 | */ | ||
6831 | static void | ||
6832 | _evas_textblock_node_format_free(Evas_Object_Textblock *o, | ||
6833 | Evas_Object_Textblock_Node_Format *n) | ||
6834 | { | ||
6835 | if (!n) return; | ||
6836 | eina_stringshare_del(n->format); | ||
6837 | eina_stringshare_del(n->orig_format); | ||
6838 | if (n->anchor == ANCHOR_ITEM) | ||
6839 | o->anchors_item = eina_list_remove(o->anchors_item, n); | ||
6840 | else if (n->anchor == ANCHOR_A) | ||
6841 | o->anchors_a = eina_list_remove(o->anchors_a, n); | ||
6842 | free(n); | ||
6843 | } | ||
6844 | |||
6845 | /** | ||
6846 | * @internal | ||
6847 | * Create a new format node. | ||
6848 | * | ||
6849 | * @param format the text to create the format node from. | ||
6850 | * @param o the textblock object. | ||
6851 | * @return Returns the new format node | ||
6852 | */ | ||
6853 | static Evas_Object_Textblock_Node_Format * | ||
6854 | _evas_textblock_node_format_new(Evas_Object_Textblock *o, const char *_format) | ||
6855 | { | ||
6856 | Evas_Object_Textblock_Node_Format *n; | ||
6857 | const char *format = _format; | ||
6858 | |||
6859 | n = calloc(1, sizeof(Evas_Object_Textblock_Node_Format)); | ||
6860 | /* Create orig_format and format */ | ||
6861 | if (format[0] == '<') | ||
6862 | { | ||
6863 | const char *match; | ||
6864 | size_t format_len; | ||
6865 | size_t replace_len; | ||
6866 | |||
6867 | format++; /* Advance after '<' */ | ||
6868 | format_len = strlen(format); | ||
6869 | if (format[format_len - 1] == '>') | ||
6870 | format_len--; /* We don't care about '>' */ | ||
6871 | |||
6872 | match = _style_match_tag(o->style, format, format_len, &replace_len); | ||
6873 | if (match) | ||
6874 | { | ||
6875 | if ((match[0] == '+') || (match[0] == '-')) | ||
6876 | { | ||
6877 | char *norm_format; | ||
6878 | norm_format = malloc(format_len + 2 + 1); | ||
6879 | memcpy(norm_format, match, 2); | ||
6880 | memcpy(norm_format + 2, format, format_len); | ||
6881 | norm_format[format_len + 2] = '\0'; | ||
6882 | n->orig_format = | ||
6883 | eina_stringshare_add_length(norm_format, format_len + 2); | ||
6884 | free(norm_format); | ||
6885 | } | ||
6886 | else | ||
6887 | { | ||
6888 | n->orig_format = | ||
6889 | eina_stringshare_add_length(format, format_len); | ||
6890 | } | ||
6891 | n->format = eina_stringshare_add(match); | ||
6892 | } | ||
6893 | else | ||
6894 | { | ||
6895 | char *norm_format; | ||
6896 | |||
6897 | norm_format = malloc(format_len + 2 + 1); | ||
6898 | if (norm_format) | ||
6899 | { | ||
6900 | if (format[0] == '/') | ||
6901 | { | ||
6902 | memcpy(norm_format, "- ", 2); | ||
6903 | memcpy(norm_format + 2, format + 1, format_len - 1); | ||
6904 | norm_format[format_len + 2 - 1] = '\0'; | ||
6905 | } | ||
6906 | else | ||
6907 | { | ||
6908 | memcpy(norm_format, "+ ", 2); | ||
6909 | memcpy(norm_format + 2, format, format_len); | ||
6910 | norm_format[format_len + 2] = '\0'; | ||
6911 | } | ||
6912 | n->orig_format = eina_stringshare_add(norm_format); | ||
6913 | free(norm_format); | ||
6914 | } | ||
6915 | n->format = eina_stringshare_ref(n->orig_format); | ||
6916 | } | ||
6917 | } | ||
6918 | /* Just use as is, it's a special format. */ | ||
6919 | else | ||
6920 | { | ||
6921 | n->orig_format = eina_stringshare_add(format); | ||
6922 | n->format = eina_stringshare_ref(n->orig_format); | ||
6923 | } | ||
6924 | |||
6925 | format = n->format; | ||
6926 | |||
6927 | _evas_textblock_format_is_visible(n, format); | ||
6928 | if (n->anchor == ANCHOR_A) | ||
6929 | { | ||
6930 | o->anchors_a = eina_list_append(o->anchors_a, n); | ||
6931 | } | ||
6932 | else if (n->anchor == ANCHOR_ITEM) | ||
6933 | { | ||
6934 | o->anchors_item = eina_list_append(o->anchors_item, n); | ||
6935 | } | ||
6936 | n->is_new = EINA_TRUE; | ||
6937 | |||
6938 | return n; | ||
6939 | } | ||
6940 | |||
6941 | static Eina_Bool | ||
6942 | _evas_textblock_cursor_is_at_the_end(const Evas_Textblock_Cursor *cur) | ||
6943 | { | ||
6944 | const Eina_Unicode *text; | ||
6945 | |||
6946 | if (!cur) return EINA_FALSE; | ||
6947 | if (!cur->node) return EINA_FALSE; | ||
6948 | text = eina_ustrbuf_string_get(cur->node->unicode); | ||
6949 | return ((text[cur->pos] == 0) && (!EINA_INLIST_GET(cur->node)->next)) ? | ||
6950 | EINA_TRUE : EINA_FALSE; | ||
6951 | } | ||
6952 | |||
6953 | EAPI Eina_Bool | ||
6954 | evas_textblock_cursor_format_append(Evas_Textblock_Cursor *cur, const char *format) | ||
6955 | { | ||
6956 | Evas_Object_Textblock *o; | ||
6957 | Evas_Object_Textblock_Node_Format *n; | ||
6958 | Eina_Bool is_visible; | ||
6959 | |||
6960 | if (!cur) return EINA_FALSE; | ||
6961 | if ((!format) || (format[0] == 0)) return EINA_FALSE; | ||
6962 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
6963 | /* We should always have at least one text node */ | ||
6964 | if (!o->text_nodes) | ||
6965 | { | ||
6966 | evas_textblock_cursor_text_prepend(cur, ""); | ||
6967 | } | ||
6968 | |||
6969 | n = _evas_textblock_node_format_new(o, format); | ||
6970 | is_visible = n->visible; | ||
6971 | format = n->format; | ||
6972 | if (!cur->node) | ||
6973 | { | ||
6974 | o->format_nodes = _NODE_FORMAT(eina_inlist_append( | ||
6975 | EINA_INLIST_GET(o->format_nodes), | ||
6976 | EINA_INLIST_GET(n))); | ||
6977 | cur->pos = 0; | ||
6978 | n->text_node = (EINA_INLIST_GET(n)->prev) ? | ||
6979 | _NODE_FORMAT(EINA_INLIST_GET(n)->prev)->text_node : | ||
6980 | o->text_nodes; | ||
6981 | cur->node = n->text_node; | ||
6982 | } | ||
6983 | else | ||
6984 | { | ||
6985 | Evas_Object_Textblock_Node_Format *fmt; | ||
6986 | fmt = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); | ||
6987 | n->text_node = cur->node; | ||
6988 | if (!fmt) | ||
6989 | { | ||
6990 | o->format_nodes = _NODE_FORMAT(eina_inlist_prepend( | ||
6991 | EINA_INLIST_GET(o->format_nodes), | ||
6992 | EINA_INLIST_GET(n))); | ||
6993 | n->offset = cur->pos; | ||
6994 | } | ||
6995 | else | ||
6996 | { | ||
6997 | if (evas_textblock_cursor_format_is_visible_get(cur)) | ||
6998 | { | ||
6999 | o->format_nodes = _NODE_FORMAT(eina_inlist_prepend_relative( | ||
7000 | EINA_INLIST_GET(o->format_nodes), | ||
7001 | EINA_INLIST_GET(n), | ||
7002 | EINA_INLIST_GET(fmt) | ||
7003 | )); | ||
7004 | n->offset = fmt->offset; | ||
7005 | if (fmt->text_node->format_node == fmt) | ||
7006 | { | ||
7007 | fmt->text_node->format_node = n; | ||
7008 | } | ||
7009 | } | ||
7010 | else | ||
7011 | { | ||
7012 | fmt = _evas_textblock_node_format_last_at_off(fmt); | ||
7013 | o->format_nodes = _NODE_FORMAT(eina_inlist_append_relative( | ||
7014 | EINA_INLIST_GET(o->format_nodes), | ||
7015 | EINA_INLIST_GET(n), | ||
7016 | EINA_INLIST_GET(fmt) | ||
7017 | )); | ||
7018 | if (fmt->text_node != cur->node) | ||
7019 | { | ||
7020 | n->offset = cur->pos; | ||
7021 | } | ||
7022 | else | ||
7023 | { | ||
7024 | n->offset = cur->pos - | ||
7025 | _evas_textblock_node_format_pos_get(fmt); | ||
7026 | } | ||
7027 | } | ||
7028 | } | ||
7029 | /* Adjust differently if we insert a format char */ | ||
7030 | if (is_visible) | ||
7031 | { | ||
7032 | _evas_textblock_node_format_adjust_offset(o, cur->node, n, | ||
7033 | -(n->offset - 1)); | ||
7034 | } | ||
7035 | else | ||
7036 | { | ||
7037 | _evas_textblock_node_format_adjust_offset(o, cur->node, n, | ||
7038 | -n->offset); | ||
7039 | } | ||
7040 | |||
7041 | if (!fmt || (fmt->text_node != cur->node)) | ||
7042 | { | ||
7043 | cur->node->format_node = n; | ||
7044 | } | ||
7045 | } | ||
7046 | if (is_visible && cur->node) | ||
7047 | { | ||
7048 | Eina_Unicode insert_char; | ||
7049 | /* Insert a visual representation according to the type of the | ||
7050 | format */ | ||
7051 | if (_IS_PARAGRAPH_SEPARATOR(o, format)) | ||
7052 | insert_char = _PARAGRAPH_SEPARATOR; | ||
7053 | else if (_IS_LINE_SEPARATOR(format)) | ||
7054 | insert_char = '\n'; | ||
7055 | else if (_IS_TAB(format)) | ||
7056 | insert_char = '\t'; | ||
7057 | else | ||
7058 | insert_char = EVAS_TEXTBLOCK_REPLACEMENT_CHAR; | ||
7059 | |||
7060 | eina_ustrbuf_insert_char(cur->node->unicode, insert_char, cur->pos); | ||
7061 | |||
7062 | /* Advance all the cursors after our cursor */ | ||
7063 | _evas_textblock_cursors_update_offset(cur, cur->node, cur->pos, 1); | ||
7064 | if (_IS_PARAGRAPH_SEPARATOR(o, format)) | ||
7065 | { | ||
7066 | _evas_textblock_cursor_break_paragraph(cur, n); | ||
7067 | } | ||
7068 | else | ||
7069 | { | ||
7070 | /* Handle visible format nodes here */ | ||
7071 | cur->node->dirty = EINA_TRUE; | ||
7072 | n->is_new = EINA_FALSE; | ||
7073 | } | ||
7074 | } | ||
7075 | else | ||
7076 | { | ||
7077 | o->format_changed = EINA_TRUE; | ||
7078 | } | ||
7079 | |||
7080 | _evas_textblock_changed(o, cur->obj); | ||
7081 | |||
7082 | if (!o->cursor->node) | ||
7083 | o->cursor->node = o->text_nodes; | ||
7084 | return is_visible; | ||
7085 | } | ||
7086 | |||
7087 | EAPI Eina_Bool | ||
7088 | evas_textblock_cursor_format_prepend(Evas_Textblock_Cursor *cur, const char *format) | ||
7089 | { | ||
7090 | Eina_Bool is_visible; | ||
7091 | /* append is essentially prepend without advancing */ | ||
7092 | is_visible = evas_textblock_cursor_format_append(cur, format); | ||
7093 | if (is_visible) | ||
7094 | { | ||
7095 | /* Advance after the replacement char */ | ||
7096 | evas_textblock_cursor_char_next(cur); | ||
7097 | } | ||
7098 | |||
7099 | return is_visible; | ||
7100 | } | ||
7101 | |||
7102 | |||
7103 | EAPI void | ||
7104 | evas_textblock_cursor_char_delete(Evas_Textblock_Cursor *cur) | ||
7105 | { | ||
7106 | Evas_Object_Textblock *o; | ||
7107 | Evas_Object_Textblock_Node_Text *n, *n2; | ||
7108 | const Eina_Unicode *text; | ||
7109 | int chr, ind, ppos; | ||
7110 | |||
7111 | if (!cur || !cur->node) return; | ||
7112 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
7113 | n = cur->node; | ||
7114 | |||
7115 | text = eina_ustrbuf_string_get(n->unicode); | ||
7116 | ind = cur->pos; | ||
7117 | if (text[ind]) | ||
7118 | chr = text[ind++]; | ||
7119 | else | ||
7120 | chr = 0; | ||
7121 | |||
7122 | if (chr == 0) return; | ||
7123 | ppos = cur->pos; | ||
7124 | eina_ustrbuf_remove(n->unicode, cur->pos, ind); | ||
7125 | /* Remove a format node if needed, and remove the char only if the | ||
7126 | * fmt node is not visible */ | ||
7127 | { | ||
7128 | Eina_Bool should_merge = EINA_FALSE; | ||
7129 | Evas_Object_Textblock_Node_Format *fmt, *fmt2; | ||
7130 | fmt = _evas_textblock_cursor_node_format_at_pos_get(cur); | ||
7131 | if (fmt) | ||
7132 | { | ||
7133 | const char *format = NULL; | ||
7134 | Evas_Object_Textblock_Node_Format *last_fmt; | ||
7135 | /* If there's a PS it must be the last become it delimits paragraphs */ | ||
7136 | last_fmt = _evas_textblock_node_format_last_at_off(fmt); | ||
7137 | format = last_fmt->format; | ||
7138 | if (format && _IS_PARAGRAPH_SEPARATOR(o, format)) | ||
7139 | { | ||
7140 | /* If it was a paragraph separator, we should merge the | ||
7141 | * current with the next, there must be a next. */ | ||
7142 | should_merge = EINA_TRUE; | ||
7143 | } | ||
7144 | /* If a singnular, mark as invisible, so we'll delete it. */ | ||
7145 | if (!format || ((*format != '+') && (*format != '-'))) | ||
7146 | { | ||
7147 | last_fmt->visible = EINA_FALSE; | ||
7148 | } | ||
7149 | } | ||
7150 | |||
7151 | fmt2 = _evas_textblock_cursor_node_format_before_or_at_pos_get(cur); | ||
7152 | fmt2 = _evas_textblock_node_format_last_at_off(fmt2); | ||
7153 | _evas_textblock_node_format_adjust_offset(o, cur->node, fmt2, | ||
7154 | -(ind - cur->pos)); | ||
7155 | |||
7156 | if (should_merge) | ||
7157 | { | ||
7158 | _evas_textblock_cursor_nodes_merge(cur); | ||
7159 | } | ||
7160 | |||
7161 | _evas_textblock_node_format_remove_matching(o, fmt); | ||
7162 | } | ||
7163 | |||
7164 | if (cur->pos == eina_ustrbuf_length_get(n->unicode)) | ||
7165 | { | ||
7166 | n2 = _NODE_TEXT(EINA_INLIST_GET(n)->next); | ||
7167 | if (n2) | ||
7168 | { | ||
7169 | cur->node = n2; | ||
7170 | cur->pos = 0; | ||
7171 | } | ||
7172 | } | ||
7173 | |||
7174 | _evas_textblock_cursors_update_offset(cur, n, ppos, -(ind - ppos)); | ||
7175 | _evas_textblock_changed(o, cur->obj); | ||
7176 | cur->node->dirty = EINA_TRUE; | ||
7177 | } | ||
7178 | |||
7179 | EAPI void | ||
7180 | evas_textblock_cursor_range_delete(Evas_Textblock_Cursor *cur1, Evas_Textblock_Cursor *cur2) | ||
7181 | { | ||
7182 | Evas_Object_Textblock_Node_Format *fnode = NULL; | ||
7183 | Evas_Object_Textblock *o; | ||
7184 | Evas_Object_Textblock_Node_Text *n1, *n2; | ||
7185 | Eina_Bool should_merge = EINA_FALSE, reset_cursor = EINA_FALSE; | ||
7186 | |||
7187 | if (!cur1 || !cur1->node) return; | ||
7188 | if (!cur2 || !cur2->node) return; | ||
7189 | if (cur1->obj != cur2->obj) return; | ||
7190 | o = (Evas_Object_Textblock *)(cur1->obj->object_data); | ||
7191 | if (evas_textblock_cursor_compare(cur1, cur2) > 0) | ||
7192 | { | ||
7193 | Evas_Textblock_Cursor *tc; | ||
7194 | |||
7195 | tc = cur1; | ||
7196 | cur1 = cur2; | ||
7197 | cur2 = tc; | ||
7198 | } | ||
7199 | n1 = cur1->node; | ||
7200 | n2 = cur2->node; | ||
7201 | if ((evas_textblock_cursor_compare(o->cursor, cur1) >= 0) && | ||
7202 | (evas_textblock_cursor_compare(cur2, o->cursor) >= 0)) | ||
7203 | { | ||
7204 | reset_cursor = EINA_TRUE; | ||
7205 | } | ||
7206 | |||
7207 | |||
7208 | if (n1 == n2) | ||
7209 | { | ||
7210 | if ((cur1->pos == 0) && | ||
7211 | (cur2->pos == eina_ustrbuf_length_get(n1->unicode))) | ||
7212 | { | ||
7213 | _evas_textblock_node_text_remove_formats_between(o, n1, 0, -1); | ||
7214 | } | ||
7215 | else | ||
7216 | { | ||
7217 | should_merge = _evas_textblock_node_text_adjust_offsets_to_start(o, | ||
7218 | n1, cur1->pos, cur2->pos); | ||
7219 | } | ||
7220 | eina_ustrbuf_remove(n1->unicode, cur1->pos, cur2->pos); | ||
7221 | _evas_textblock_cursors_update_offset(cur1, cur1->node, cur1->pos, - (cur2->pos - cur1->pos)); | ||
7222 | } | ||
7223 | else | ||
7224 | { | ||
7225 | Evas_Object_Textblock_Node_Text *n; | ||
7226 | int len; | ||
7227 | _evas_textblock_node_text_adjust_offsets_to_start(o, n1, cur1->pos, -1); | ||
7228 | n = _NODE_TEXT(EINA_INLIST_GET(n1)->next); | ||
7229 | /* Remove all the text nodes between */ | ||
7230 | while (n && (n != n2)) | ||
7231 | { | ||
7232 | Evas_Object_Textblock_Node_Text *nnode; | ||
7233 | |||
7234 | nnode = _NODE_TEXT(EINA_INLIST_GET(n)->next); | ||
7235 | _evas_textblock_cursors_set_node(o, n, n1); | ||
7236 | _evas_textblock_node_text_remove(o, n); | ||
7237 | n = nnode; | ||
7238 | } | ||
7239 | should_merge = _evas_textblock_node_text_adjust_offsets_to_start(o, n2, | ||
7240 | 0, cur2->pos); | ||
7241 | |||
7242 | /* Remove the formats and the strings in the first and last nodes */ | ||
7243 | len = eina_ustrbuf_length_get(n1->unicode); | ||
7244 | eina_ustrbuf_remove(n1->unicode, cur1->pos, len); | ||
7245 | eina_ustrbuf_remove(n2->unicode, 0, cur2->pos); | ||
7246 | /* Merge the nodes because we removed the PS */ | ||
7247 | _evas_textblock_cursors_update_offset(cur1, cur1->node, cur1->pos, | ||
7248 | - cur1->pos); | ||
7249 | _evas_textblock_cursors_update_offset(cur2, cur2->node, 0, - cur2->pos); | ||
7250 | _evas_textblock_nodes_merge(o, n1); | ||
7251 | } | ||
7252 | fnode = _evas_textblock_cursor_node_format_at_pos_get(cur1); | ||
7253 | |||
7254 | if (should_merge) | ||
7255 | { | ||
7256 | /* We call this function instead of the cursor one because we already | ||
7257 | * updated the cursors */ | ||
7258 | _evas_textblock_nodes_merge(o, n1); | ||
7259 | } | ||
7260 | _evas_textblock_node_format_remove_matching(o, fnode); | ||
7261 | |||
7262 | evas_textblock_cursor_copy(cur1, cur2); | ||
7263 | if (reset_cursor) | ||
7264 | evas_textblock_cursor_copy(cur1, o->cursor); | ||
7265 | |||
7266 | _evas_textblock_changed(o, cur1->obj); | ||
7267 | n1->dirty = n2->dirty = EINA_TRUE; | ||
7268 | } | ||
7269 | |||
7270 | |||
7271 | EAPI char * | ||
7272 | evas_textblock_cursor_content_get(const Evas_Textblock_Cursor *cur) | ||
7273 | { | ||
7274 | const Eina_Unicode *ustr; | ||
7275 | Eina_Unicode buf[2]; | ||
7276 | char *s; | ||
7277 | if (!cur || !cur->node) return NULL; | ||
7278 | if (evas_textblock_cursor_format_is_visible_get(cur)) | ||
7279 | { | ||
7280 | size_t len; | ||
7281 | const char *fstr; | ||
7282 | char *ret; | ||
7283 | int pop = 0; | ||
7284 | fstr = evas_textblock_node_format_text_get( | ||
7285 | _evas_textblock_node_visible_at_pos_get( | ||
7286 | evas_textblock_cursor_format_get(cur))); | ||
7287 | |||
7288 | if (!fstr) | ||
7289 | return NULL; | ||
7290 | |||
7291 | if (*fstr == '-') pop = 1; | ||
7292 | while ((*fstr == ' ') || (*fstr == '+') || (*fstr == '-')) fstr++; | ||
7293 | len = strlen(fstr); | ||
7294 | |||
7295 | { | ||
7296 | char *tmp; | ||
7297 | if (pop) | ||
7298 | { | ||
7299 | ret = tmp = malloc(len + 3 + 1); /* </> and the null */ | ||
7300 | memcpy(tmp, "</", 2); | ||
7301 | tmp += 2; | ||
7302 | } | ||
7303 | else | ||
7304 | { | ||
7305 | ret = tmp = malloc(len + 2 + 1); /* <> and the null */ | ||
7306 | *tmp = '<'; | ||
7307 | tmp++; | ||
7308 | } | ||
7309 | memcpy(tmp, fstr, len); | ||
7310 | memcpy(tmp + len, ">", 2); /* Including the null */ | ||
7311 | } | ||
7312 | |||
7313 | return ret; | ||
7314 | } | ||
7315 | |||
7316 | ustr = eina_ustrbuf_string_get(cur->node->unicode); | ||
7317 | buf[0] = ustr[cur->pos]; | ||
7318 | buf[1] = 0; | ||
7319 | s = eina_unicode_unicode_to_utf8(buf, NULL); | ||
7320 | |||
7321 | return s; | ||
7322 | } | ||
7323 | |||
7324 | static char * | ||
7325 | _evas_textblock_cursor_range_text_markup_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2) | ||
7326 | { | ||
7327 | Evas_Object_Textblock *o; | ||
7328 | Evas_Object_Textblock_Node_Text *tnode; | ||
7329 | Eina_Strbuf *buf; | ||
7330 | Evas_Textblock_Cursor *cur2; | ||
7331 | buf = eina_strbuf_new(); | ||
7332 | |||
7333 | if (!cur1 || !cur1->node) return NULL; | ||
7334 | if (!_cur2 || !_cur2->node) return NULL; | ||
7335 | if (cur1->obj != _cur2->obj) return NULL; | ||
7336 | o = (Evas_Object_Textblock *)(cur1->obj->object_data); | ||
7337 | if (evas_textblock_cursor_compare(cur1, _cur2) > 0) | ||
7338 | { | ||
7339 | const Evas_Textblock_Cursor *tc; | ||
7340 | |||
7341 | tc = cur1; | ||
7342 | cur1 = _cur2; | ||
7343 | _cur2 = tc; | ||
7344 | } | ||
7345 | /* Work on a local copy of the cur */ | ||
7346 | cur2 = alloca(sizeof(Evas_Textblock_Cursor)); | ||
7347 | cur2->obj = _cur2->obj; | ||
7348 | evas_textblock_cursor_copy(_cur2, cur2); | ||
7349 | |||
7350 | /* Parse the text between the cursors. */ | ||
7351 | for (tnode = cur1->node ; tnode ; | ||
7352 | tnode = _NODE_TEXT(EINA_INLIST_GET(tnode)->next)) | ||
7353 | { | ||
7354 | Evas_Object_Textblock_Node_Format *fnode; | ||
7355 | Eina_Unicode *text_base, *text; | ||
7356 | int off = 0; | ||
7357 | |||
7358 | text_base = text = | ||
7359 | eina_unicode_strndup(eina_ustrbuf_string_get(tnode->unicode), | ||
7360 | eina_ustrbuf_length_get(tnode->unicode)); | ||
7361 | if (tnode == cur2->node) | ||
7362 | { | ||
7363 | fnode = _evas_textblock_node_text_get_first_format_between(tnode, | ||
7364 | cur1->pos, cur2->pos); | ||
7365 | } | ||
7366 | else if (tnode == cur1->node) | ||
7367 | { | ||
7368 | fnode = _evas_textblock_node_text_get_first_format_between(tnode, | ||
7369 | cur1->pos, -1); | ||
7370 | } | ||
7371 | else | ||
7372 | { | ||
7373 | fnode = _evas_textblock_node_text_get_first_format_between(tnode, | ||
7374 | 0, -1); | ||
7375 | } | ||
7376 | /* Init the offset so the first one will count starting from cur1->pos | ||
7377 | * and not the previous format node */ | ||
7378 | if (tnode == cur1->node) | ||
7379 | { | ||
7380 | if (fnode) | ||
7381 | { | ||
7382 | off = _evas_textblock_node_format_pos_get(fnode) - | ||
7383 | cur1->pos - fnode->offset; | ||
7384 | } | ||
7385 | text += cur1->pos; | ||
7386 | } | ||
7387 | else | ||
7388 | { | ||
7389 | off = 0; | ||
7390 | } | ||
7391 | while (fnode && (fnode->text_node == tnode)) | ||
7392 | { | ||
7393 | Eina_Unicode tmp_ch; | ||
7394 | off += fnode->offset; | ||
7395 | if ((tnode == cur2->node) && | ||
7396 | ((size_t) (text - text_base + off) >= cur2->pos)) | ||
7397 | { | ||
7398 | break; | ||
7399 | } | ||
7400 | /* No need to skip on the first run */ | ||
7401 | tmp_ch = text[off]; | ||
7402 | text[off] = 0; /* Null terminate the part of the string */ | ||
7403 | _markup_get_text_append(buf, text); | ||
7404 | _markup_get_format_append(o, buf, fnode); | ||
7405 | text[off] = tmp_ch; /* Restore the char */ | ||
7406 | text += off; | ||
7407 | if (fnode->visible) | ||
7408 | { | ||
7409 | off = -1; | ||
7410 | text++; | ||
7411 | } | ||
7412 | else | ||
7413 | { | ||
7414 | off = 0; | ||
7415 | } | ||
7416 | fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
7417 | } | ||
7418 | /* If we got to the last node, stop and add the rest outside */ | ||
7419 | if (cur2->node == tnode) | ||
7420 | { | ||
7421 | /* Add the rest, skip replacement */ | ||
7422 | /* Don't go past the second cursor pos */ | ||
7423 | text_base[cur2->pos] = '\0'; | ||
7424 | _markup_get_text_append(buf, text); | ||
7425 | free(text_base); | ||
7426 | break; | ||
7427 | } | ||
7428 | else | ||
7429 | { | ||
7430 | /* Add the rest, skip replacement */ | ||
7431 | _markup_get_text_append(buf, text); | ||
7432 | free(text_base); | ||
7433 | } | ||
7434 | } | ||
7435 | /* return the string */ | ||
7436 | { | ||
7437 | char *ret; | ||
7438 | ret = eina_strbuf_string_steal(buf); | ||
7439 | eina_strbuf_free(buf); | ||
7440 | return ret; | ||
7441 | } | ||
7442 | } | ||
7443 | |||
7444 | static char * | ||
7445 | _evas_textblock_cursor_range_text_plain_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *_cur2) | ||
7446 | { | ||
7447 | Eina_UStrbuf *buf; | ||
7448 | Evas_Object_Textblock_Node_Text *n1, *n2; | ||
7449 | Evas_Textblock_Cursor *cur2; | ||
7450 | |||
7451 | buf = eina_ustrbuf_new(); | ||
7452 | |||
7453 | if (!cur1 || !cur1->node) return NULL; | ||
7454 | if (!_cur2 || !_cur2->node) return NULL; | ||
7455 | if (cur1->obj != _cur2->obj) return NULL; | ||
7456 | if (evas_textblock_cursor_compare(cur1, _cur2) > 0) | ||
7457 | { | ||
7458 | const Evas_Textblock_Cursor *tc; | ||
7459 | |||
7460 | tc = cur1; | ||
7461 | cur1 = _cur2; | ||
7462 | _cur2 = tc; | ||
7463 | } | ||
7464 | n1 = cur1->node; | ||
7465 | n2 = _cur2->node; | ||
7466 | /* Work on a local copy of the cur */ | ||
7467 | cur2 = alloca(sizeof(Evas_Textblock_Cursor)); | ||
7468 | cur2->obj = _cur2->obj; | ||
7469 | evas_textblock_cursor_copy(_cur2, cur2); | ||
7470 | |||
7471 | |||
7472 | if (n1 == n2) | ||
7473 | { | ||
7474 | const Eina_Unicode *tmp; | ||
7475 | tmp = eina_ustrbuf_string_get(n1->unicode); | ||
7476 | eina_ustrbuf_append_length(buf, tmp + cur1->pos, cur2->pos - cur1->pos); | ||
7477 | } | ||
7478 | else | ||
7479 | { | ||
7480 | const Eina_Unicode *tmp; | ||
7481 | tmp = eina_ustrbuf_string_get(n1->unicode); | ||
7482 | eina_ustrbuf_append(buf, tmp + cur1->pos); | ||
7483 | n1 = _NODE_TEXT(EINA_INLIST_GET(n1)->next); | ||
7484 | while (n1 != n2) | ||
7485 | { | ||
7486 | tmp = eina_ustrbuf_string_get(n1->unicode); | ||
7487 | eina_ustrbuf_append_length(buf, tmp, | ||
7488 | eina_ustrbuf_length_get(n1->unicode)); | ||
7489 | n1 = _NODE_TEXT(EINA_INLIST_GET(n1)->next); | ||
7490 | } | ||
7491 | tmp = eina_ustrbuf_string_get(n2->unicode); | ||
7492 | eina_ustrbuf_append_length(buf, tmp, cur2->pos); | ||
7493 | } | ||
7494 | |||
7495 | /* Free and return */ | ||
7496 | { | ||
7497 | char *ret; | ||
7498 | ret = eina_unicode_unicode_to_utf8(eina_ustrbuf_string_get(buf), NULL); | ||
7499 | eina_ustrbuf_free(buf); | ||
7500 | return ret; | ||
7501 | } | ||
7502 | } | ||
7503 | |||
7504 | EAPI Eina_List * | ||
7505 | evas_textblock_cursor_range_formats_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) | ||
7506 | { | ||
7507 | Evas_Object *obj = cur1->obj; | ||
7508 | Eina_List *ret = NULL; | ||
7509 | Evas_Object_Textblock_Node_Text *n1, *n2; | ||
7510 | Evas_Object_Textblock_Node_Format *first, *last; | ||
7511 | TB_HEAD_RETURN(NULL); | ||
7512 | if (!cur1 || !cur1->node) return NULL; | ||
7513 | if (!cur2 || !cur2->node) return NULL; | ||
7514 | if (cur1->obj != cur2->obj) return NULL; | ||
7515 | if (evas_textblock_cursor_compare(cur1, cur2) > 0) | ||
7516 | { | ||
7517 | const Evas_Textblock_Cursor *tc; | ||
7518 | |||
7519 | tc = cur1; | ||
7520 | cur1 = cur2; | ||
7521 | cur2 = tc; | ||
7522 | } | ||
7523 | n1 = cur1->node; | ||
7524 | n2 = cur2->node; | ||
7525 | |||
7526 | /* FIXME: Change first and last getting to format_before_or_at_pos_get */ | ||
7527 | |||
7528 | last = n2->format_node; | ||
7529 | |||
7530 | /* If n2->format_node is NULL, we don't have formats in the tb/range. */ | ||
7531 | if (!last) | ||
7532 | return NULL; | ||
7533 | /* If the found format is on our text node, we should go to the last | ||
7534 | * one, otherwise, the one we found is good enough. */ | ||
7535 | if (last->text_node == n2) | ||
7536 | { | ||
7537 | Evas_Object_Textblock_Node_Format *fnode = last; | ||
7538 | while (fnode && (fnode->text_node == n2)) | ||
7539 | { | ||
7540 | last = fnode; | ||
7541 | fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
7542 | } | ||
7543 | } | ||
7544 | |||
7545 | /* If the first format node is within the range (i.e points to n1) or if | ||
7546 | * we have other formats in the range, go through them */ | ||
7547 | first = n1->format_node; | ||
7548 | if ((first->text_node == n1) || (first != last)) | ||
7549 | { | ||
7550 | Evas_Object_Textblock_Node_Format *fnode = first; | ||
7551 | /* Go to the first one in the range */ | ||
7552 | if (first->text_node != n1) | ||
7553 | { | ||
7554 | first = _NODE_FORMAT(EINA_INLIST_GET(first)->next); | ||
7555 | } | ||
7556 | |||
7557 | while (fnode) | ||
7558 | { | ||
7559 | ret = eina_list_append(ret, fnode); | ||
7560 | if (fnode == last) | ||
7561 | break; | ||
7562 | fnode = _NODE_FORMAT(EINA_INLIST_GET(fnode)->next); | ||
7563 | } | ||
7564 | } | ||
7565 | |||
7566 | return ret; | ||
7567 | |||
7568 | } | ||
7569 | |||
7570 | EAPI char * | ||
7571 | evas_textblock_cursor_range_text_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2, Evas_Textblock_Text_Type format) | ||
7572 | { | ||
7573 | if (format == EVAS_TEXTBLOCK_TEXT_MARKUP) | ||
7574 | return _evas_textblock_cursor_range_text_markup_get(cur1, cur2); | ||
7575 | else if (format == EVAS_TEXTBLOCK_TEXT_PLAIN) | ||
7576 | return _evas_textblock_cursor_range_text_plain_get(cur1, cur2); | ||
7577 | else | ||
7578 | return NULL; /* Not yet supported */ | ||
7579 | } | ||
7580 | |||
7581 | EAPI const char * | ||
7582 | evas_textblock_cursor_paragraph_text_get(const Evas_Textblock_Cursor *cur) | ||
7583 | { | ||
7584 | Evas_Textblock_Cursor cur1, cur2; | ||
7585 | if (!cur) return NULL; | ||
7586 | if (!cur->node) return NULL; | ||
7587 | if (cur->node->utf8) | ||
7588 | { | ||
7589 | free(cur->node->utf8); | ||
7590 | } | ||
7591 | cur1.obj = cur2.obj = cur->obj; | ||
7592 | cur1.node = cur2.node = cur->node; | ||
7593 | evas_textblock_cursor_paragraph_char_first(&cur1); | ||
7594 | evas_textblock_cursor_paragraph_char_last(&cur2); | ||
7595 | |||
7596 | cur->node->utf8 = evas_textblock_cursor_range_text_get(&cur1, &cur2, | ||
7597 | EVAS_TEXTBLOCK_TEXT_MARKUP); | ||
7598 | return cur->node->utf8; | ||
7599 | } | ||
7600 | |||
7601 | EAPI int | ||
7602 | evas_textblock_cursor_paragraph_text_length_get(const Evas_Textblock_Cursor *cur) | ||
7603 | { | ||
7604 | int len; | ||
7605 | if (!cur) return -1; | ||
7606 | if (!cur->node) return -1; | ||
7607 | len = eina_ustrbuf_length_get(cur->node->unicode); | ||
7608 | |||
7609 | if (EINA_INLIST_GET(cur->node)->next) | ||
7610 | return len - 1; /* Remove the paragraph separator */ | ||
7611 | else | ||
7612 | return len; | ||
7613 | } | ||
7614 | |||
7615 | EAPI const Evas_Object_Textblock_Node_Format * | ||
7616 | evas_textblock_cursor_format_get(const Evas_Textblock_Cursor *cur) | ||
7617 | { | ||
7618 | if (!cur) return NULL; | ||
7619 | if (!cur->node) return NULL; | ||
7620 | return _evas_textblock_cursor_node_format_at_pos_get(cur); | ||
7621 | } | ||
7622 | |||
7623 | EAPI const char * | ||
7624 | evas_textblock_node_format_text_get(const Evas_Object_Textblock_Node_Format *fmt) | ||
7625 | { | ||
7626 | if (!fmt) return NULL; | ||
7627 | return fmt->orig_format; | ||
7628 | } | ||
7629 | |||
7630 | EAPI void | ||
7631 | evas_textblock_cursor_at_format_set(Evas_Textblock_Cursor *cur, const Evas_Object_Textblock_Node_Format *fmt) | ||
7632 | { | ||
7633 | if (!fmt || !cur) return; | ||
7634 | cur->node = fmt->text_node; | ||
7635 | cur->pos = _evas_textblock_node_format_pos_get(fmt); | ||
7636 | } | ||
7637 | |||
7638 | EAPI Eina_Bool | ||
7639 | evas_textblock_cursor_format_is_visible_get(const Evas_Textblock_Cursor *cur) | ||
7640 | { | ||
7641 | const Eina_Unicode *text; | ||
7642 | |||
7643 | if (!cur) return EINA_FALSE; | ||
7644 | if (!cur->node) return EINA_FALSE; | ||
7645 | text = eina_ustrbuf_string_get(cur->node->unicode); | ||
7646 | return EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(text[cur->pos]); | ||
7647 | } | ||
7648 | |||
7649 | EAPI int | ||
7650 | evas_textblock_cursor_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *dir, Evas_Textblock_Cursor_Type ctype) | ||
7651 | { | ||
7652 | int ret = -1; | ||
7653 | const Evas_Textblock_Cursor *dir_cur; | ||
7654 | Evas_Textblock_Cursor cur2; | ||
7655 | Evas_Object_Textblock *o; | ||
7656 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
7657 | if (!o->formatted.valid) _relayout(cur->obj); | ||
7658 | |||
7659 | dir_cur = cur; | ||
7660 | if (ctype == EVAS_TEXTBLOCK_CURSOR_UNDER) | ||
7661 | { | ||
7662 | ret = evas_textblock_cursor_pen_geometry_get(cur, cx, cy, cw, ch); | ||
7663 | } | ||
7664 | else if (ctype == EVAS_TEXTBLOCK_CURSOR_BEFORE) | ||
7665 | { | ||
7666 | /* In the case of a "before cursor", we should get the coordinates | ||
7667 | * of just after the previous char (which in bidi text may not be | ||
7668 | * just before the current char). */ | ||
7669 | Evas_Coord x, y, h, w; | ||
7670 | Evas_Object_Textblock_Node_Format *fmt; | ||
7671 | |||
7672 | /* If it's at the end of the line, we want to get the position, not | ||
7673 | * the position of the previous */ | ||
7674 | if ((cur->pos > 0) && !_evas_textblock_cursor_is_at_the_end(cur)) | ||
7675 | { | ||
7676 | Eina_Bool before_char = EINA_FALSE; | ||
7677 | cur2.obj = cur->obj; | ||
7678 | evas_textblock_cursor_copy(cur, &cur2); | ||
7679 | evas_textblock_cursor_char_prev(&cur2); | ||
7680 | |||
7681 | fmt = _evas_textblock_cursor_node_format_at_pos_get(&cur2); | ||
7682 | |||
7683 | if (!fmt || !_IS_LINE_SEPARATOR(fmt->format)) | ||
7684 | { | ||
7685 | dir_cur = &cur2; | ||
7686 | before_char = EINA_FALSE; | ||
7687 | } | ||
7688 | else | ||
7689 | { | ||
7690 | before_char = EINA_TRUE; | ||
7691 | } | ||
7692 | ret = evas_textblock_cursor_pen_geometry_get( | ||
7693 | dir_cur, &x, &y, &w, &h); | ||
7694 | #ifdef BIDI_SUPPORT | ||
7695 | /* Adjust if the char is an rtl char */ | ||
7696 | if (ret >= 0) | ||
7697 | { | ||
7698 | Eina_Bool is_rtl = EINA_FALSE; | ||
7699 | if (dir_cur->node->par->is_bidi) | ||
7700 | { | ||
7701 | Evas_Object_Textblock_Line *ln; | ||
7702 | Evas_Object_Textblock_Item *it; | ||
7703 | _find_layout_item_match(dir_cur, &ln, &it); | ||
7704 | if ((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) && | ||
7705 | (_ITEM_TEXT(it)->text_props.bidi.dir == | ||
7706 | EVAS_BIDI_DIRECTION_RTL)) | ||
7707 | is_rtl = EINA_TRUE; | ||
7708 | else if ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) && | ||
7709 | (_ITEM_FORMAT(it)->bidi_dir == | ||
7710 | EVAS_BIDI_DIRECTION_RTL)) | ||
7711 | is_rtl = EINA_TRUE; | ||
7712 | } | ||
7713 | |||
7714 | if ((!before_char && is_rtl) || | ||
7715 | (before_char && !is_rtl)) | ||
7716 | { | ||
7717 | /* Just don't advance the width */ | ||
7718 | w = 0; | ||
7719 | } | ||
7720 | } | ||
7721 | #endif | ||
7722 | } | ||
7723 | else if (cur->pos == 0) | ||
7724 | { | ||
7725 | ret = evas_textblock_cursor_pen_geometry_get( | ||
7726 | dir_cur, &x, &y, &w, &h); | ||
7727 | #ifdef BIDI_SUPPORT | ||
7728 | Eina_Bool is_rtl = EINA_FALSE; | ||
7729 | if (dir_cur->node && dir_cur->node->par->is_bidi) | ||
7730 | { | ||
7731 | Evas_Object_Textblock_Line *ln; | ||
7732 | Evas_Object_Textblock_Item *it; | ||
7733 | _find_layout_item_match(dir_cur, &ln, &it); | ||
7734 | if ((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) && | ||
7735 | (_ITEM_TEXT(it)->text_props.bidi.dir == | ||
7736 | EVAS_BIDI_DIRECTION_RTL)) | ||
7737 | is_rtl = EINA_TRUE; | ||
7738 | else if ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) && | ||
7739 | (_ITEM_FORMAT(it)->bidi_dir == | ||
7740 | EVAS_BIDI_DIRECTION_RTL)) | ||
7741 | is_rtl = EINA_TRUE; | ||
7742 | } | ||
7743 | |||
7744 | /* Adjust if the char is an rtl char */ | ||
7745 | if ((ret >= 0) && (!is_rtl)) | ||
7746 | { | ||
7747 | /* Just don't advance the width */ | ||
7748 | w = 0; | ||
7749 | } | ||
7750 | #endif | ||
7751 | } | ||
7752 | else | ||
7753 | { | ||
7754 | ret = evas_textblock_cursor_pen_geometry_get( | ||
7755 | dir_cur, &x, &y, &w, &h); | ||
7756 | } | ||
7757 | if (ret >= 0) | ||
7758 | { | ||
7759 | if (cx) *cx = x + w; | ||
7760 | if (cy) *cy = y; | ||
7761 | if (cw) *cw = 0; | ||
7762 | if (ch) *ch = h; | ||
7763 | } | ||
7764 | } | ||
7765 | |||
7766 | if (dir && dir_cur && dir_cur->node) | ||
7767 | { | ||
7768 | #ifdef BIDI_SUPPORT | ||
7769 | Eina_Bool is_rtl = EINA_FALSE; | ||
7770 | if (dir_cur->node->par->is_bidi) | ||
7771 | { | ||
7772 | Evas_Object_Textblock_Line *ln; | ||
7773 | Evas_Object_Textblock_Item *it; | ||
7774 | _find_layout_item_match(dir_cur, &ln, &it); | ||
7775 | if ((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) && | ||
7776 | (_ITEM_TEXT(it)->text_props.bidi.dir == | ||
7777 | EVAS_BIDI_DIRECTION_RTL)) | ||
7778 | is_rtl = EINA_TRUE; | ||
7779 | else if ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) && | ||
7780 | (_ITEM_FORMAT(it)->bidi_dir == | ||
7781 | EVAS_BIDI_DIRECTION_RTL)) | ||
7782 | is_rtl = EINA_TRUE; | ||
7783 | } | ||
7784 | |||
7785 | if (_evas_textblock_cursor_is_at_the_end(dir_cur) && (dir_cur->pos > 0)) | ||
7786 | { | ||
7787 | *dir = (is_rtl) ? | ||
7788 | EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR; | ||
7789 | } | ||
7790 | else if (dir_cur->pos > 0) | ||
7791 | { | ||
7792 | *dir = (is_rtl) ? | ||
7793 | EVAS_BIDI_DIRECTION_RTL : EVAS_BIDI_DIRECTION_LTR; | ||
7794 | } | ||
7795 | else | ||
7796 | #endif | ||
7797 | { | ||
7798 | *dir = EVAS_BIDI_DIRECTION_LTR; | ||
7799 | } | ||
7800 | } | ||
7801 | return ret; | ||
7802 | } | ||
7803 | |||
7804 | /** | ||
7805 | * @internal | ||
7806 | * Returns the geometry/pen position (depending on query_func) of the char | ||
7807 | * at pos. | ||
7808 | * | ||
7809 | * @param cur the position of the char. | ||
7810 | * @param query_func the query function to use. | ||
7811 | * @param cx the x of the char (or pen_x in the case of pen position). | ||
7812 | * @param cy the y of the char. | ||
7813 | * @param cw the w of the char (or advance in the case pen position). | ||
7814 | * @param ch the h of the char. | ||
7815 | * @return line number of the char on success, -1 on error. | ||
7816 | */ | ||
7817 | static int | ||
7818 | _evas_textblock_cursor_char_pen_geometry_common_get(int (*query_func) (void *data, Evas_Font_Set *font, const Evas_Text_Props *intl_props, int pos, int *cx, int *cy, int *cw, int *ch), const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) | ||
7819 | { | ||
7820 | Evas_Object_Textblock *o; | ||
7821 | Evas_Object_Textblock_Line *ln = NULL; | ||
7822 | Evas_Object_Textblock_Item *it = NULL; | ||
7823 | Evas_Object_Textblock_Text_Item *ti = NULL; | ||
7824 | Evas_Object_Textblock_Format_Item *fi = NULL; | ||
7825 | int x = 0, y = 0, w = 0, h = 0; | ||
7826 | int pos; | ||
7827 | Eina_Bool previous_format; | ||
7828 | |||
7829 | if (!cur) return -1; | ||
7830 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
7831 | if (!o->formatted.valid) _relayout(cur->obj); | ||
7832 | |||
7833 | if (!cur->node) | ||
7834 | { | ||
7835 | if (!o->text_nodes) | ||
7836 | { | ||
7837 | if (!o->paragraphs) return -1; | ||
7838 | ln = o->paragraphs->lines; | ||
7839 | if (!ln) return -1; | ||
7840 | if (cx) *cx = ln->x; | ||
7841 | if (cy) *cy = ln->par->y + ln->y; | ||
7842 | if (cw) *cw = ln->w; | ||
7843 | if (ch) *ch = ln->h; | ||
7844 | return ln->par->line_no + ln->line_no; | ||
7845 | } | ||
7846 | else | ||
7847 | return -1; | ||
7848 | } | ||
7849 | |||
7850 | previous_format = _find_layout_item_match(cur, &ln, &it); | ||
7851 | if (!it) | ||
7852 | { | ||
7853 | return -1; | ||
7854 | } | ||
7855 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
7856 | { | ||
7857 | ti = _ITEM_TEXT(it); | ||
7858 | } | ||
7859 | else | ||
7860 | { | ||
7861 | fi = _ITEM_FORMAT(it); | ||
7862 | } | ||
7863 | |||
7864 | if (ln && ti) | ||
7865 | { | ||
7866 | pos = cur->pos - ti->parent.text_pos; | ||
7867 | |||
7868 | if (pos < 0) pos = 0; | ||
7869 | if (ti->parent.format->font.font) | ||
7870 | { | ||
7871 | query_func(cur->ENDT, | ||
7872 | ti->parent.format->font.font, | ||
7873 | &ti->text_props, | ||
7874 | pos, | ||
7875 | &x, &y, &w, &h); | ||
7876 | } | ||
7877 | |||
7878 | x += ln->x + _ITEM(ti)->x; | ||
7879 | |||
7880 | if (x < ln->x) | ||
7881 | { | ||
7882 | x = ln->x; | ||
7883 | } | ||
7884 | y = ln->par->y + ln->y; | ||
7885 | h = ln->h; | ||
7886 | } | ||
7887 | else if (ln && fi) | ||
7888 | { | ||
7889 | if (previous_format) | ||
7890 | { | ||
7891 | if (_IS_LINE_SEPARATOR(fi->item)) | ||
7892 | { | ||
7893 | x = 0; | ||
7894 | y = ln->par->y + ln->y + ln->h; | ||
7895 | } | ||
7896 | else | ||
7897 | { | ||
7898 | #ifdef BIDI_SUPPORT | ||
7899 | if (ln->par->direction == EVAS_BIDI_DIRECTION_RTL) | ||
7900 | { | ||
7901 | x = ln->x; | ||
7902 | } | ||
7903 | else | ||
7904 | #endif | ||
7905 | { | ||
7906 | x = ln->x + ln->w; | ||
7907 | } | ||
7908 | y = ln->par->y + ln->y; | ||
7909 | } | ||
7910 | w = 0; | ||
7911 | h = ln->h; | ||
7912 | } | ||
7913 | else | ||
7914 | { | ||
7915 | x = ln->x + _ITEM(fi)->x; | ||
7916 | y = ln->par->y + ln->y; | ||
7917 | w = _ITEM(fi)->w; | ||
7918 | h = ln->h; | ||
7919 | } | ||
7920 | } | ||
7921 | else | ||
7922 | { | ||
7923 | return -1; | ||
7924 | } | ||
7925 | if (cx) *cx = x; | ||
7926 | if (cy) *cy = y; | ||
7927 | if (cw) *cw = w; | ||
7928 | if (ch) *ch = h; | ||
7929 | return ln->par->line_no + ln->line_no; | ||
7930 | } | ||
7931 | |||
7932 | EAPI int | ||
7933 | evas_textblock_cursor_char_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) | ||
7934 | { | ||
7935 | return _evas_textblock_cursor_char_pen_geometry_common_get( | ||
7936 | cur->ENFN->font_char_coords_get, cur, cx, cy, cw, ch); | ||
7937 | } | ||
7938 | |||
7939 | EAPI int | ||
7940 | evas_textblock_cursor_pen_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) | ||
7941 | { | ||
7942 | return _evas_textblock_cursor_char_pen_geometry_common_get( | ||
7943 | cur->ENFN->font_pen_coords_get, cur, cx, cy, cw, ch); | ||
7944 | } | ||
7945 | |||
7946 | EAPI int | ||
7947 | evas_textblock_cursor_line_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) | ||
7948 | { | ||
7949 | Evas_Object_Textblock *o; | ||
7950 | Evas_Object_Textblock_Line *ln = NULL; | ||
7951 | Evas_Object_Textblock_Item *it = NULL; | ||
7952 | int x, y, w, h; | ||
7953 | |||
7954 | if (!cur) return -1; | ||
7955 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
7956 | if (!o->formatted.valid) _relayout(cur->obj); | ||
7957 | if (!cur->node) | ||
7958 | { | ||
7959 | ln = o->paragraphs->lines; | ||
7960 | } | ||
7961 | else | ||
7962 | { | ||
7963 | _find_layout_item_match(cur, &ln, &it); | ||
7964 | } | ||
7965 | if (!ln) return -1; | ||
7966 | x = ln->x; | ||
7967 | y = ln->par->y + ln->y; | ||
7968 | w = ln->w; | ||
7969 | h = ln->h; | ||
7970 | if (cx) *cx = x; | ||
7971 | if (cy) *cy = y; | ||
7972 | if (cw) *cw = w; | ||
7973 | if (ch) *ch = h; | ||
7974 | return ln->par->line_no + ln->line_no; | ||
7975 | } | ||
7976 | |||
7977 | EAPI Eina_Bool | ||
7978 | evas_textblock_cursor_visible_range_get(Evas_Textblock_Cursor *start, Evas_Textblock_Cursor *end) | ||
7979 | { | ||
7980 | Evas *e; | ||
7981 | Evas_Coord cy, ch; | ||
7982 | Evas_Object *obj = start->obj; | ||
7983 | TB_HEAD_RETURN(EINA_FALSE); | ||
7984 | e = evas_object_evas_get(obj); | ||
7985 | cy = 0 - obj->cur.geometry.y; | ||
7986 | ch = e->viewport.h; | ||
7987 | evas_textblock_cursor_line_coord_set(start, cy); | ||
7988 | evas_textblock_cursor_line_coord_set(end, cy + ch); | ||
7989 | evas_textblock_cursor_line_char_last(end); | ||
7990 | |||
7991 | return EINA_TRUE; | ||
7992 | } | ||
7993 | |||
7994 | EAPI Eina_Bool | ||
7995 | evas_textblock_cursor_char_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord x, Evas_Coord y) | ||
7996 | { | ||
7997 | Evas_Object_Textblock *o; | ||
7998 | Evas_Object_Textblock_Paragraph *found_par; | ||
7999 | Evas_Object_Textblock_Line *ln; | ||
8000 | Evas_Object_Textblock_Item *it = NULL; | ||
8001 | |||
8002 | if (!cur) return EINA_FALSE; | ||
8003 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
8004 | if (!o->formatted.valid) _relayout(cur->obj); | ||
8005 | x += o->style_pad.l; | ||
8006 | y += o->style_pad.t; | ||
8007 | |||
8008 | found_par = _layout_find_paragraph_by_y(o, y); | ||
8009 | if (found_par) | ||
8010 | { | ||
8011 | _layout_paragraph_render(o, found_par); | ||
8012 | EINA_INLIST_FOREACH(found_par->lines, ln) | ||
8013 | { | ||
8014 | if (ln->par->y + ln->y > y) break; | ||
8015 | if ((ln->par->y + ln->y <= y) && ((ln->par->y + ln->y + ln->h) > y)) | ||
8016 | { | ||
8017 | /* If before or after the line, go to start/end according | ||
8018 | * to paragraph direction. */ | ||
8019 | if (x < ln->x) | ||
8020 | { | ||
8021 | cur->pos = ln->items->text_pos; | ||
8022 | cur->node = found_par->text_node; | ||
8023 | if (found_par->direction == EVAS_BIDI_DIRECTION_RTL) | ||
8024 | { | ||
8025 | evas_textblock_cursor_line_char_last(cur); | ||
8026 | } | ||
8027 | else | ||
8028 | { | ||
8029 | evas_textblock_cursor_line_char_first(cur); | ||
8030 | } | ||
8031 | return EINA_TRUE; | ||
8032 | } | ||
8033 | else if (x >= ln->x + ln->w) | ||
8034 | { | ||
8035 | cur->pos = ln->items->text_pos; | ||
8036 | cur->node = found_par->text_node; | ||
8037 | if (found_par->direction == EVAS_BIDI_DIRECTION_RTL) | ||
8038 | { | ||
8039 | evas_textblock_cursor_line_char_first(cur); | ||
8040 | } | ||
8041 | else | ||
8042 | { | ||
8043 | evas_textblock_cursor_line_char_last(cur); | ||
8044 | } | ||
8045 | return EINA_TRUE; | ||
8046 | } | ||
8047 | |||
8048 | EINA_INLIST_FOREACH(ln->items, it) | ||
8049 | { | ||
8050 | if (((it->x + ln->x) <= x) && (((it->x + ln->x) + it->adv) > x)) | ||
8051 | { | ||
8052 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
8053 | { | ||
8054 | int pos; | ||
8055 | int cx, cy, cw, ch; | ||
8056 | Evas_Object_Textblock_Text_Item *ti; | ||
8057 | ti = _ITEM_TEXT(it); | ||
8058 | |||
8059 | pos = -1; | ||
8060 | if (ti->parent.format->font.font) | ||
8061 | pos = cur->ENFN->font_char_at_coords_get( | ||
8062 | cur->ENDT, | ||
8063 | ti->parent.format->font.font, | ||
8064 | &ti->text_props, | ||
8065 | x - it->x - ln->x, 0, | ||
8066 | &cx, &cy, &cw, &ch); | ||
8067 | if (pos < 0) | ||
8068 | return EINA_FALSE; | ||
8069 | cur->pos = pos + it->text_pos; | ||
8070 | cur->node = it->text_node; | ||
8071 | return EINA_TRUE; | ||
8072 | } | ||
8073 | else | ||
8074 | { | ||
8075 | Evas_Object_Textblock_Format_Item *fi; | ||
8076 | fi = _ITEM_FORMAT(it); | ||
8077 | cur->pos = fi->parent.text_pos; | ||
8078 | cur->node = found_par->text_node; | ||
8079 | return EINA_TRUE; | ||
8080 | } | ||
8081 | } | ||
8082 | } | ||
8083 | } | ||
8084 | } | ||
8085 | } | ||
8086 | else if (o->paragraphs && (y >= o->paragraphs->y + o->formatted.h)) | ||
8087 | { | ||
8088 | /* If we are after the last paragraph, use the last position in the | ||
8089 | * text. */ | ||
8090 | evas_textblock_cursor_paragraph_last(cur); | ||
8091 | return EINA_TRUE; | ||
8092 | } | ||
8093 | else if (o->paragraphs && (y < o->paragraphs->y)) | ||
8094 | { | ||
8095 | evas_textblock_cursor_paragraph_first(cur); | ||
8096 | return EINA_TRUE; | ||
8097 | } | ||
8098 | |||
8099 | return EINA_FALSE; | ||
8100 | } | ||
8101 | |||
8102 | EAPI int | ||
8103 | evas_textblock_cursor_line_coord_set(Evas_Textblock_Cursor *cur, Evas_Coord y) | ||
8104 | { | ||
8105 | Evas_Object_Textblock *o; | ||
8106 | Evas_Object_Textblock_Paragraph *found_par; | ||
8107 | Evas_Object_Textblock_Line *ln; | ||
8108 | |||
8109 | if (!cur) return -1; | ||
8110 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
8111 | if (!o->formatted.valid) _relayout(cur->obj); | ||
8112 | y += o->style_pad.t; | ||
8113 | |||
8114 | found_par = _layout_find_paragraph_by_y(o, y); | ||
8115 | |||
8116 | if (found_par) | ||
8117 | { | ||
8118 | _layout_paragraph_render(o, found_par); | ||
8119 | EINA_INLIST_FOREACH(found_par->lines, ln) | ||
8120 | { | ||
8121 | if (ln->par->y + ln->y > y) break; | ||
8122 | if ((ln->par->y + ln->y <= y) && ((ln->par->y + ln->y + ln->h) > y)) | ||
8123 | { | ||
8124 | evas_textblock_cursor_line_set(cur, ln->par->line_no + | ||
8125 | ln->line_no); | ||
8126 | return ln->par->line_no + ln->line_no; | ||
8127 | } | ||
8128 | } | ||
8129 | } | ||
8130 | else if (o->paragraphs && (y >= o->paragraphs->y + o->formatted.h)) | ||
8131 | { | ||
8132 | int line_no = 0; | ||
8133 | /* If we are after the last paragraph, use the last position in the | ||
8134 | * text. */ | ||
8135 | evas_textblock_cursor_paragraph_last(cur); | ||
8136 | if (cur->node && cur->node->par) | ||
8137 | { | ||
8138 | line_no = cur->node->par->line_no; | ||
8139 | if (cur->node->par->lines) | ||
8140 | { | ||
8141 | line_no += ((Evas_Object_Textblock_Line *) | ||
8142 | EINA_INLIST_GET(cur->node->par->lines)->last)->line_no; | ||
8143 | } | ||
8144 | } | ||
8145 | return line_no; | ||
8146 | } | ||
8147 | else if (o->paragraphs && (y < o->paragraphs->y)) | ||
8148 | { | ||
8149 | int line_no = 0; | ||
8150 | evas_textblock_cursor_paragraph_first(cur); | ||
8151 | if (cur->node && cur->node->par) | ||
8152 | { | ||
8153 | line_no = cur->node->par->line_no; | ||
8154 | } | ||
8155 | return line_no; | ||
8156 | } | ||
8157 | return -1; | ||
8158 | } | ||
8159 | |||
8160 | /** | ||
8161 | * @internal | ||
8162 | * Updates x and w according to the text direction, position in text and | ||
8163 | * if it's a special case switch | ||
8164 | * | ||
8165 | * @param ti the text item we are working on | ||
8166 | * @param x the current x (we get) and the x we return | ||
8167 | * @param w the current w (we get) and the w we return | ||
8168 | * @param start if this is the first item or not | ||
8169 | * @param switch_items toogles item switching (rtl cases) | ||
8170 | */ | ||
8171 | static void | ||
8172 | _evas_textblock_range_calc_x_w(const Evas_Object_Textblock_Item *it, | ||
8173 | Evas_Coord *x, Evas_Coord *w, Eina_Bool start, Eina_Bool switch_items) | ||
8174 | { | ||
8175 | if ((start && !switch_items) || (!start && switch_items)) | ||
8176 | { | ||
8177 | #ifdef BIDI_SUPPORT | ||
8178 | if (((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) && | ||
8179 | _ITEM_TEXT(it)->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL) | ||
8180 | || | ||
8181 | ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) && | ||
8182 | _ITEM_FORMAT(it)->bidi_dir == EVAS_BIDI_DIRECTION_RTL)) | ||
8183 | { | ||
8184 | *w = *x + *w; | ||
8185 | *x = 0; | ||
8186 | } | ||
8187 | else | ||
8188 | #endif | ||
8189 | { | ||
8190 | *w = it->adv - *x; | ||
8191 | } | ||
8192 | } | ||
8193 | else | ||
8194 | { | ||
8195 | #ifdef BIDI_SUPPORT | ||
8196 | if (((it->type == EVAS_TEXTBLOCK_ITEM_TEXT) && | ||
8197 | _ITEM_TEXT(it)->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL) | ||
8198 | || | ||
8199 | ((it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) && | ||
8200 | _ITEM_FORMAT(it)->bidi_dir == EVAS_BIDI_DIRECTION_RTL)) | ||
8201 | { | ||
8202 | *x = *x + *w; | ||
8203 | *w = it->adv - *x; | ||
8204 | } | ||
8205 | else | ||
8206 | #endif | ||
8207 | { | ||
8208 | *w = *x; | ||
8209 | *x = 0; | ||
8210 | } | ||
8211 | } | ||
8212 | |||
8213 | } | ||
8214 | |||
8215 | /** | ||
8216 | * @internal | ||
8217 | * Returns the geometry of the range in line ln. Cur1 is the start cursor, | ||
8218 | * cur2 is the end cursor, NULL means from the start or to the end accordingly. | ||
8219 | * Assumes that ln is valid, and that at least one of cur1 and cur2 is not NULL. | ||
8220 | * | ||
8221 | * @param ln the line to work on. | ||
8222 | * @param cur1 the start cursor | ||
8223 | * @param cur2 the end cursor | ||
8224 | * @return Returns the geometry of the range | ||
8225 | */ | ||
8226 | static Eina_List * | ||
8227 | _evas_textblock_cursor_range_in_line_geometry_get( | ||
8228 | const Evas_Object_Textblock_Line *ln, const Evas_Textblock_Cursor *cur1, | ||
8229 | const Evas_Textblock_Cursor *cur2) | ||
8230 | { | ||
8231 | Evas_Object_Textblock_Item *it; | ||
8232 | Evas_Object_Textblock_Item *it1, *it2; | ||
8233 | Eina_List *rects = NULL; | ||
8234 | Evas_Textblock_Rectangle *tr; | ||
8235 | size_t start, end; | ||
8236 | Eina_Bool switch_items; | ||
8237 | const Evas_Textblock_Cursor *cur; | ||
8238 | |||
8239 | cur = (cur1) ? cur1 : cur2; | ||
8240 | |||
8241 | if (!cur) return NULL; | ||
8242 | |||
8243 | /* Find the first and last items */ | ||
8244 | it1 = it2 = NULL; | ||
8245 | start = end = 0; | ||
8246 | EINA_INLIST_FOREACH(ln->items, it) | ||
8247 | { | ||
8248 | size_t item_len; | ||
8249 | item_len = (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? | ||
8250 | _ITEM_TEXT(it)->text_props.text_len | ||
8251 | : 1; | ||
8252 | if ((!cur1 || (cur1->pos < it->text_pos + item_len)) && | ||
8253 | (!cur2 || (cur2->pos >= it->text_pos))) | ||
8254 | { | ||
8255 | if (!it1) | ||
8256 | { | ||
8257 | it1 = it; | ||
8258 | start = item_len; /* start stores the first item_len */ | ||
8259 | } | ||
8260 | it2 = it; | ||
8261 | end = item_len; /* end stores the last item_len */ | ||
8262 | } | ||
8263 | } | ||
8264 | |||
8265 | /* If we couldn't find even one item, return */ | ||
8266 | if (!it1) return NULL; | ||
8267 | |||
8268 | /* If the first item is logically before or equal the second item | ||
8269 | * we have to set start and end differently than in the other case */ | ||
8270 | if (it1->text_pos <= it2->text_pos) | ||
8271 | { | ||
8272 | start = (cur1) ? (cur1->pos - it1->text_pos) : 0; | ||
8273 | end = (cur2) ? (cur2->pos - it2->text_pos) : end; | ||
8274 | switch_items = EINA_FALSE; | ||
8275 | } | ||
8276 | else | ||
8277 | { | ||
8278 | start = (cur2) ? (cur2->pos - it1->text_pos) : start; | ||
8279 | end = (cur1) ? (cur1->pos - it2->text_pos) : 0; | ||
8280 | switch_items = EINA_TRUE; | ||
8281 | } | ||
8282 | |||
8283 | /* IMPORTANT: Don't use cur1/cur2 past this point (because they probably | ||
8284 | * don't make sense anymore. That's why there are start and end), | ||
8285 | * unless you know what you are doing */ | ||
8286 | |||
8287 | /* Special case when they share the same item and it's a text item */ | ||
8288 | if ((it1 == it2) && (it1->type == EVAS_TEXTBLOCK_ITEM_TEXT)) | ||
8289 | { | ||
8290 | Evas_Coord x1, w1, x2, w2; | ||
8291 | Evas_Coord x, w, y, h; | ||
8292 | Evas_Object_Textblock_Text_Item *ti; | ||
8293 | int ret = 0; | ||
8294 | |||
8295 | ti = _ITEM_TEXT(it1); | ||
8296 | if (ti->parent.format->font.font) | ||
8297 | { | ||
8298 | ret = cur->ENFN->font_pen_coords_get(cur->ENDT, | ||
8299 | ti->parent.format->font.font, | ||
8300 | &ti->text_props, | ||
8301 | start, | ||
8302 | &x1, &y, &w1, &h); | ||
8303 | } | ||
8304 | if (!ret) | ||
8305 | { | ||
8306 | return NULL; | ||
8307 | } | ||
8308 | ret = cur->ENFN->font_pen_coords_get(cur->ENDT, | ||
8309 | ti->parent.format->font.font, | ||
8310 | &ti->text_props, | ||
8311 | end, | ||
8312 | &x2, &y, &w2, &h); | ||
8313 | if (!ret) | ||
8314 | { | ||
8315 | return NULL; | ||
8316 | } | ||
8317 | |||
8318 | /* Make x2 the one on the right */ | ||
8319 | if (x2 < x1) | ||
8320 | { | ||
8321 | Evas_Coord tmp; | ||
8322 | tmp = x1; | ||
8323 | x1 = x2; | ||
8324 | x2 = tmp; | ||
8325 | |||
8326 | tmp = w1; | ||
8327 | w1 = w2; | ||
8328 | w2 = tmp; | ||
8329 | } | ||
8330 | |||
8331 | #ifdef BIDI_SUPPORT | ||
8332 | if (ti->text_props.bidi.dir == EVAS_BIDI_DIRECTION_RTL) | ||
8333 | { | ||
8334 | x = x1 + w1; | ||
8335 | w = x2 + w2 - x; | ||
8336 | } | ||
8337 | else | ||
8338 | #endif | ||
8339 | { | ||
8340 | x = x1; | ||
8341 | w = x2 - x1; | ||
8342 | } | ||
8343 | if (w > 0) | ||
8344 | { | ||
8345 | tr = calloc(1, sizeof(Evas_Textblock_Rectangle)); | ||
8346 | rects = eina_list_append(rects, tr); | ||
8347 | tr->x = ln->x + it1->x + x; | ||
8348 | tr->y = ln->par->y + ln->y; | ||
8349 | tr->h = ln->h; | ||
8350 | tr->w = w; | ||
8351 | } | ||
8352 | } | ||
8353 | else if (it1 != it2) | ||
8354 | { | ||
8355 | /* Get the middle items */ | ||
8356 | Evas_Coord min_x, max_x; | ||
8357 | Evas_Coord x, w; | ||
8358 | it = _ITEM(EINA_INLIST_GET(it1)->next); | ||
8359 | min_x = max_x = it->x; | ||
8360 | |||
8361 | if (it1->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
8362 | { | ||
8363 | Evas_Coord y, h; | ||
8364 | Evas_Object_Textblock_Text_Item *ti; | ||
8365 | int ret; | ||
8366 | ti = _ITEM_TEXT(it1); | ||
8367 | |||
8368 | ret = cur->ENFN->font_pen_coords_get(cur->ENDT, | ||
8369 | ti->parent.format->font.font, | ||
8370 | &ti->text_props, | ||
8371 | start, | ||
8372 | &x, &y, &w, &h); | ||
8373 | if (!ret) | ||
8374 | { | ||
8375 | /* BUG! Skip the first item */ | ||
8376 | x = w = 0; | ||
8377 | } | ||
8378 | else | ||
8379 | { | ||
8380 | _evas_textblock_range_calc_x_w(it1, &x, &w, EINA_TRUE, | ||
8381 | switch_items); | ||
8382 | } | ||
8383 | } | ||
8384 | else | ||
8385 | { | ||
8386 | x = 0; | ||
8387 | w = it1->w; | ||
8388 | _evas_textblock_range_calc_x_w(it1, &x, &w, EINA_TRUE, | ||
8389 | switch_items); | ||
8390 | } | ||
8391 | if (w > 0) | ||
8392 | { | ||
8393 | tr = calloc(1, sizeof(Evas_Textblock_Rectangle)); | ||
8394 | rects = eina_list_append(rects, tr); | ||
8395 | tr->x = ln->x + it1->x + x; | ||
8396 | tr->y = ln->par->y + ln->y; | ||
8397 | tr->h = ln->h; | ||
8398 | tr->w = w; | ||
8399 | } | ||
8400 | |||
8401 | while (it && (it != it2)) | ||
8402 | { | ||
8403 | max_x = it->x + it->adv; | ||
8404 | it = (Evas_Object_Textblock_Item *) EINA_INLIST_GET(it)->next; | ||
8405 | } | ||
8406 | if (min_x != max_x) | ||
8407 | { | ||
8408 | tr = calloc(1, sizeof(Evas_Textblock_Rectangle)); | ||
8409 | rects = eina_list_append(rects, tr); | ||
8410 | tr->x = ln->x + min_x; | ||
8411 | tr->y = ln->par->y + ln->y; | ||
8412 | tr->h = ln->h; | ||
8413 | tr->w = max_x - min_x; | ||
8414 | } | ||
8415 | if (it2->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
8416 | { | ||
8417 | Evas_Coord y, h; | ||
8418 | Evas_Object_Textblock_Text_Item *ti; | ||
8419 | int ret; | ||
8420 | ti = _ITEM_TEXT(it2); | ||
8421 | |||
8422 | ret = cur->ENFN->font_pen_coords_get(cur->ENDT, | ||
8423 | ti->parent.format->font.font, | ||
8424 | &ti->text_props, | ||
8425 | end, | ||
8426 | &x, &y, &w, &h); | ||
8427 | if (!ret) | ||
8428 | { | ||
8429 | /* BUG! skip the last item */ | ||
8430 | x = w = 0; | ||
8431 | } | ||
8432 | else | ||
8433 | { | ||
8434 | _evas_textblock_range_calc_x_w(it2, &x, &w, EINA_FALSE, | ||
8435 | switch_items); | ||
8436 | } | ||
8437 | } | ||
8438 | else | ||
8439 | { | ||
8440 | x = 0; | ||
8441 | w = it2->w; | ||
8442 | _evas_textblock_range_calc_x_w(it2, &x, &w, EINA_FALSE, | ||
8443 | switch_items); | ||
8444 | } | ||
8445 | if (w > 0) | ||
8446 | { | ||
8447 | tr = calloc(1, sizeof(Evas_Textblock_Rectangle)); | ||
8448 | rects = eina_list_append(rects, tr); | ||
8449 | tr->x = ln->x + it2->x + x; | ||
8450 | tr->y = ln->par->y + ln->y; | ||
8451 | tr->h = ln->h; | ||
8452 | tr->w = w; | ||
8453 | } | ||
8454 | } | ||
8455 | return rects; | ||
8456 | } | ||
8457 | |||
8458 | EAPI Eina_List * | ||
8459 | evas_textblock_cursor_range_geometry_get(const Evas_Textblock_Cursor *cur1, const Evas_Textblock_Cursor *cur2) | ||
8460 | { | ||
8461 | Evas_Object_Textblock *o; | ||
8462 | Evas_Object_Textblock_Line *ln1, *ln2; | ||
8463 | Evas_Object_Textblock_Item *it1, *it2; | ||
8464 | Eina_List *rects = NULL; | ||
8465 | Evas_Textblock_Rectangle *tr; | ||
8466 | |||
8467 | if (!cur1 || !cur1->node) return NULL; | ||
8468 | if (!cur2 || !cur2->node) return NULL; | ||
8469 | if (cur1->obj != cur2->obj) return NULL; | ||
8470 | o = (Evas_Object_Textblock *)(cur1->obj->object_data); | ||
8471 | if (!o->formatted.valid) _relayout(cur1->obj); | ||
8472 | if (evas_textblock_cursor_compare(cur1, cur2) > 0) | ||
8473 | { | ||
8474 | const Evas_Textblock_Cursor *tc; | ||
8475 | |||
8476 | tc = cur1; | ||
8477 | cur1 = cur2; | ||
8478 | cur2 = tc; | ||
8479 | } | ||
8480 | |||
8481 | ln1 = ln2 = NULL; | ||
8482 | it1 = it2 = NULL; | ||
8483 | _find_layout_item_match(cur1, &ln1, &it1); | ||
8484 | if (!ln1 || !it1) return NULL; | ||
8485 | _find_layout_item_match(cur2, &ln2, &it2); | ||
8486 | if (!ln2 || !it2) return NULL; | ||
8487 | |||
8488 | if (ln1 == ln2) | ||
8489 | { | ||
8490 | rects = _evas_textblock_cursor_range_in_line_geometry_get(ln1, | ||
8491 | cur1, cur2); | ||
8492 | } | ||
8493 | else | ||
8494 | { | ||
8495 | Evas_Object_Textblock_Line *plni, *lni; | ||
8496 | Eina_List *rects2 = NULL; | ||
8497 | /* Handle the first line */ | ||
8498 | rects = _evas_textblock_cursor_range_in_line_geometry_get(ln1, | ||
8499 | cur1, NULL); | ||
8500 | |||
8501 | /* Handle the lines between the first and the last line */ | ||
8502 | lni = (Evas_Object_Textblock_Line *) EINA_INLIST_GET(ln1)->next; | ||
8503 | if (!lni && (ln1->par != ln2->par)) | ||
8504 | { | ||
8505 | lni = ((Evas_Object_Textblock_Paragraph *) | ||
8506 | EINA_INLIST_GET(ln1->par)->next)->lines; | ||
8507 | } | ||
8508 | while (lni && (lni != ln2)) | ||
8509 | { | ||
8510 | tr = calloc(1, sizeof(Evas_Textblock_Rectangle)); | ||
8511 | rects = eina_list_append(rects, tr); | ||
8512 | tr->x = lni->x; | ||
8513 | tr->y = lni->par->y + lni->y; | ||
8514 | tr->h = lni->h; | ||
8515 | tr->w = lni->w; | ||
8516 | plni = lni; | ||
8517 | lni = (Evas_Object_Textblock_Line *) EINA_INLIST_GET(lni)->next; | ||
8518 | if (!lni && (plni->par != ln2->par)) | ||
8519 | { | ||
8520 | lni = ((Evas_Object_Textblock_Paragraph *) | ||
8521 | EINA_INLIST_GET(plni->par)->next)->lines; | ||
8522 | } | ||
8523 | } | ||
8524 | rects2 = _evas_textblock_cursor_range_in_line_geometry_get(ln2, | ||
8525 | NULL, cur2); | ||
8526 | rects = eina_list_merge(rects, rects2); | ||
8527 | } | ||
8528 | return rects; | ||
8529 | } | ||
8530 | |||
8531 | EAPI Eina_Bool | ||
8532 | evas_textblock_cursor_format_item_geometry_get(const Evas_Textblock_Cursor *cur, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) | ||
8533 | { | ||
8534 | Evas_Object_Textblock *o; | ||
8535 | Evas_Object_Textblock_Line *ln = NULL; | ||
8536 | Evas_Object_Textblock_Format_Item *fi; | ||
8537 | Evas_Object_Textblock_Item *it = NULL; | ||
8538 | Evas_Coord x, y, w, h; | ||
8539 | |||
8540 | if (!cur || !evas_textblock_cursor_format_is_visible_get(cur)) return EINA_FALSE; | ||
8541 | o = (Evas_Object_Textblock *)(cur->obj->object_data); | ||
8542 | if (!o->formatted.valid) _relayout(cur->obj); | ||
8543 | if (!evas_textblock_cursor_format_is_visible_get(cur)) return EINA_FALSE; | ||
8544 | _find_layout_item_line_match(cur->obj, cur->node, cur->pos, &ln, &it); | ||
8545 | fi = _ITEM_FORMAT(it); | ||
8546 | if ((!ln) || (!fi)) return EINA_FALSE; | ||
8547 | x = ln->x + fi->parent.x; | ||
8548 | y = ln->par->y + ln->y + ln->baseline + fi->y; | ||
8549 | w = fi->parent.w; | ||
8550 | h = fi->parent.h; | ||
8551 | if (cx) *cx = x; | ||
8552 | if (cy) *cy = y; | ||
8553 | if (cw) *cw = w; | ||
8554 | if (ch) *ch = h; | ||
8555 | return EINA_TRUE; | ||
8556 | } | ||
8557 | |||
8558 | EAPI Eina_Bool | ||
8559 | evas_textblock_cursor_eol_get(const Evas_Textblock_Cursor *cur) | ||
8560 | { | ||
8561 | Eina_Bool ret = EINA_FALSE; | ||
8562 | Evas_Textblock_Cursor cur2; | ||
8563 | if (!cur) return EINA_FALSE; | ||
8564 | |||
8565 | cur2.obj = cur->obj; | ||
8566 | evas_textblock_cursor_copy(cur, &cur2); | ||
8567 | evas_textblock_cursor_line_char_last(&cur2); | ||
8568 | if (cur2.pos == cur->pos) | ||
8569 | { | ||
8570 | ret = EINA_TRUE; | ||
8571 | } | ||
8572 | return ret; | ||
8573 | } | ||
8574 | |||
8575 | /* general controls */ | ||
8576 | EAPI Eina_Bool | ||
8577 | evas_object_textblock_line_number_geometry_get(const Evas_Object *obj, int line, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch) | ||
8578 | { | ||
8579 | Evas_Object_Textblock_Line *ln; | ||
8580 | |||
8581 | TB_HEAD_RETURN(0); | ||
8582 | ln = _find_layout_line_num(obj, line); | ||
8583 | if (!ln) return EINA_FALSE; | ||
8584 | if (cx) *cx = ln->x; | ||
8585 | if (cy) *cy = ln->par->y + ln->y; | ||
8586 | if (cw) *cw = ln->w; | ||
8587 | if (ch) *ch = ln->h; | ||
8588 | return EINA_TRUE; | ||
8589 | } | ||
8590 | |||
8591 | EAPI void | ||
8592 | evas_object_textblock_clear(Evas_Object *obj) | ||
8593 | { | ||
8594 | Eina_List *l; | ||
8595 | Evas_Textblock_Cursor *cur; | ||
8596 | |||
8597 | TB_HEAD(); | ||
8598 | if (o->paragraphs) | ||
8599 | { | ||
8600 | _paragraphs_free(obj, o->paragraphs); | ||
8601 | o->paragraphs = NULL; | ||
8602 | } | ||
8603 | |||
8604 | _nodes_clear(obj); | ||
8605 | o->cursor->node = NULL; | ||
8606 | o->cursor->pos = 0; | ||
8607 | EINA_LIST_FOREACH(o->cursors, l, cur) | ||
8608 | { | ||
8609 | cur->node = NULL; | ||
8610 | cur->pos = 0; | ||
8611 | |||
8612 | } | ||
8613 | _evas_textblock_changed(o, obj); | ||
8614 | } | ||
8615 | |||
8616 | EAPI void | ||
8617 | evas_object_textblock_size_formatted_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) | ||
8618 | { | ||
8619 | TB_HEAD(); | ||
8620 | if (!o->formatted.valid) _relayout(obj); | ||
8621 | if (w) *w = o->formatted.w; | ||
8622 | if (h) *h = o->formatted.h; | ||
8623 | } | ||
8624 | |||
8625 | static void | ||
8626 | _size_native_calc_line_finalize(const Evas_Object *obj, Eina_List *items, | ||
8627 | Evas_Coord *ascent, Evas_Coord *descent, Evas_Coord *w) | ||
8628 | { | ||
8629 | Evas_Object_Textblock_Item *it; | ||
8630 | Eina_List *i; | ||
8631 | |||
8632 | it = eina_list_data_get(items); | ||
8633 | /* If there are no text items yet, calc ascent/descent | ||
8634 | * according to the current format. */ | ||
8635 | if (it && (*ascent + *descent == 0)) | ||
8636 | _layout_format_ascent_descent_adjust(obj, ascent, descent, it->format); | ||
8637 | |||
8638 | *w = 0; | ||
8639 | /* Adjust all the item sizes according to the final line size, | ||
8640 | * and update the x positions of all the items of the line. */ | ||
8641 | EINA_LIST_FOREACH(items, i, it) | ||
8642 | { | ||
8643 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) | ||
8644 | { | ||
8645 | Evas_Coord fw, fh, fy; | ||
8646 | |||
8647 | Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it); | ||
8648 | if (!fi->formatme) goto loop_advance; | ||
8649 | _layout_calculate_format_item_size(obj, fi, ascent, | ||
8650 | descent, &fy, &fw, &fh); | ||
8651 | } | ||
8652 | |||
8653 | loop_advance: | ||
8654 | *w += it->adv; | ||
8655 | } | ||
8656 | } | ||
8657 | |||
8658 | /* FIXME: doc */ | ||
8659 | static void | ||
8660 | _size_native_calc_paragraph_size(const Evas_Object *obj, | ||
8661 | const Evas_Object_Textblock *o, | ||
8662 | const Evas_Object_Textblock_Paragraph *par, | ||
8663 | Evas_Coord *_w, Evas_Coord *_h) | ||
8664 | { | ||
8665 | Eina_List *i; | ||
8666 | Evas_Object_Textblock_Item *it; | ||
8667 | Eina_List *line_items = NULL; | ||
8668 | Evas_Coord w = 0, y = 0, wmax = 0, h = 0, ascent = 0, descent = 0; | ||
8669 | |||
8670 | EINA_LIST_FOREACH(par->logical_items, i, it) | ||
8671 | { | ||
8672 | line_items = eina_list_append(line_items, it); | ||
8673 | if (it->type == EVAS_TEXTBLOCK_ITEM_FORMAT) | ||
8674 | { | ||
8675 | Evas_Object_Textblock_Format_Item *fi = _ITEM_FORMAT(it); | ||
8676 | if (fi->item && (_IS_LINE_SEPARATOR(fi->item) || | ||
8677 | _IS_PARAGRAPH_SEPARATOR(o, fi->item))) | ||
8678 | { | ||
8679 | _size_native_calc_line_finalize(obj, line_items, &ascent, | ||
8680 | &descent, &w); | ||
8681 | |||
8682 | if (ascent + descent > h) | ||
8683 | h = ascent + descent; | ||
8684 | |||
8685 | y += h; | ||
8686 | if (w > wmax) | ||
8687 | wmax = w; | ||
8688 | h = 0; | ||
8689 | ascent = descent = 0; | ||
8690 | line_items = eina_list_free(line_items); | ||
8691 | } | ||
8692 | else | ||
8693 | { | ||
8694 | Evas_Coord fw, fh, fy; | ||
8695 | /* If there are no text items yet, calc ascent/descent | ||
8696 | * according to the current format. */ | ||
8697 | if (it && (ascent + descent == 0)) | ||
8698 | _layout_format_ascent_descent_adjust(obj, &ascent, | ||
8699 | &descent, it->format); | ||
8700 | |||
8701 | _layout_calculate_format_item_size(obj, fi, &ascent, | ||
8702 | &descent, &fy, &fw, &fh); | ||
8703 | } | ||
8704 | } | ||
8705 | else | ||
8706 | { | ||
8707 | _layout_format_ascent_descent_adjust(obj, &ascent, | ||
8708 | &descent, it->format); | ||
8709 | } | ||
8710 | } | ||
8711 | |||
8712 | _size_native_calc_line_finalize(obj, line_items, &ascent, &descent, &w); | ||
8713 | |||
8714 | line_items = eina_list_free(line_items); | ||
8715 | |||
8716 | /* Do the last addition */ | ||
8717 | if (ascent + descent > h) | ||
8718 | h = ascent + descent; | ||
8719 | |||
8720 | if (w > wmax) | ||
8721 | wmax = w; | ||
8722 | |||
8723 | *_h = y + h; | ||
8724 | *_w = wmax; | ||
8725 | } | ||
8726 | |||
8727 | EAPI void | ||
8728 | evas_object_textblock_size_native_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h) | ||
8729 | { | ||
8730 | TB_HEAD(); | ||
8731 | if (!o->native.valid) | ||
8732 | { | ||
8733 | Evas_Coord wmax = 0, hmax = 0; | ||
8734 | Evas_Object_Textblock_Paragraph *par; | ||
8735 | /* We just want the layout objects to update, should probably | ||
8736 | * split that. */ | ||
8737 | if (!o->formatted.valid) _relayout(obj); | ||
8738 | EINA_INLIST_FOREACH(o->paragraphs, par) | ||
8739 | { | ||
8740 | Evas_Coord tw, th; | ||
8741 | _size_native_calc_paragraph_size(obj, o, par, &tw, &th); | ||
8742 | if (tw > wmax) | ||
8743 | wmax = tw; | ||
8744 | hmax += th; | ||
8745 | } | ||
8746 | |||
8747 | o->native.w = wmax; | ||
8748 | o->native.h = hmax; | ||
8749 | |||
8750 | o->native.valid = 1; | ||
8751 | o->content_changed = 0; | ||
8752 | o->format_changed = EINA_FALSE; | ||
8753 | } | ||
8754 | if (w) *w = o->native.w; | ||
8755 | if (h) *h = o->native.h; | ||
8756 | } | ||
8757 | |||
8758 | EAPI void | ||
8759 | evas_object_textblock_style_insets_get(const Evas_Object *obj, Evas_Coord *l, Evas_Coord *r, Evas_Coord *t, Evas_Coord *b) | ||
8760 | { | ||
8761 | TB_HEAD(); | ||
8762 | if (!o->formatted.valid) _relayout(obj); | ||
8763 | if (l) *l = o->style_pad.l; | ||
8764 | if (r) *r = o->style_pad.r; | ||
8765 | if (t) *t = o->style_pad.t; | ||
8766 | if (b) *b = o->style_pad.b; | ||
8767 | } | ||
8768 | |||
8769 | /** @internal | ||
8770 | * FIXME: DELETE ME! DELETE ME! | ||
8771 | * This is an ugly workaround to get around the fact that | ||
8772 | * evas_object_textblock_coords_recalc isn't really called when it's supposed | ||
8773 | * to. When that bug is fixed please remove this. */ | ||
8774 | static void | ||
8775 | _workaround_object_coords_recalc(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__) | ||
8776 | { | ||
8777 | evas_object_textblock_coords_recalc(obj); | ||
8778 | } | ||
8779 | |||
8780 | /* all nice and private */ | ||
8781 | static void | ||
8782 | evas_object_textblock_init(Evas_Object *obj) | ||
8783 | { | ||
8784 | Evas_Object_Textblock *o; | ||
8785 | #ifdef HAVE_LINEBREAK | ||
8786 | static Eina_Bool linebreak_init = EINA_FALSE; | ||
8787 | if (!linebreak_init) | ||
8788 | { | ||
8789 | linebreak_init = EINA_TRUE; | ||
8790 | init_linebreak(); | ||
8791 | } | ||
8792 | #endif | ||
8793 | |||
8794 | /* alloc image ob, setup methods and default values */ | ||
8795 | obj->object_data = evas_object_textblock_new(); | ||
8796 | /* set up default settings for this kind of object */ | ||
8797 | obj->cur.color.r = 255; | ||
8798 | obj->cur.color.g = 255; | ||
8799 | obj->cur.color.b = 255; | ||
8800 | obj->cur.color.a = 255; | ||
8801 | obj->cur.geometry.x = 0.0; | ||
8802 | obj->cur.geometry.y = 0.0; | ||
8803 | obj->cur.geometry.w = 0.0; | ||
8804 | obj->cur.geometry.h = 0.0; | ||
8805 | obj->cur.layer = 0; | ||
8806 | /* set up object-specific settings */ | ||
8807 | obj->prev = obj->cur; | ||
8808 | /* set up methods (compulsory) */ | ||
8809 | obj->func = &object_func; | ||
8810 | obj->type = o_type; | ||
8811 | |||
8812 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
8813 | o->cursor->obj = obj; | ||
8814 | o->legacy_newline = EINA_TRUE; | ||
8815 | evas_object_event_callback_priority_add(obj, EVAS_CALLBACK_RESIZE, -1000, | ||
8816 | _workaround_object_coords_recalc, NULL); | ||
8817 | } | ||
8818 | |||
8819 | static void * | ||
8820 | evas_object_textblock_new(void) | ||
8821 | { | ||
8822 | Evas_Object_Textblock *o; | ||
8823 | |||
8824 | /* alloc obj private data */ | ||
8825 | EVAS_MEMPOOL_INIT(_mp_obj, "evas_object_textblock", Evas_Object_Textblock, 64, NULL); | ||
8826 | o = EVAS_MEMPOOL_ALLOC(_mp_obj, Evas_Object_Textblock); | ||
8827 | if (!o) return NULL; | ||
8828 | EVAS_MEMPOOL_PREP(_mp_obj, o, Evas_Object_Textblock); | ||
8829 | o->magic = MAGIC_OBJ_TEXTBLOCK; | ||
8830 | o->cursor = calloc(1, sizeof(Evas_Textblock_Cursor)); | ||
8831 | _format_command_init(); | ||
8832 | return o; | ||
8833 | } | ||
8834 | |||
8835 | static void | ||
8836 | evas_object_textblock_free(Evas_Object *obj) | ||
8837 | { | ||
8838 | Evas_Object_Textblock *o; | ||
8839 | |||
8840 | evas_object_textblock_clear(obj); | ||
8841 | evas_object_textblock_style_set(obj, NULL); | ||
8842 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
8843 | free(o->cursor); | ||
8844 | while (o->cursors) | ||
8845 | { | ||
8846 | Evas_Textblock_Cursor *cur; | ||
8847 | |||
8848 | cur = (Evas_Textblock_Cursor *)o->cursors->data; | ||
8849 | o->cursors = eina_list_remove_list(o->cursors, o->cursors); | ||
8850 | free(cur); | ||
8851 | } | ||
8852 | if (o->repch) eina_stringshare_del(o->repch); | ||
8853 | if (o->ellip_ti) _item_free(obj, NULL, _ITEM(o->ellip_ti)); | ||
8854 | o->magic = 0; | ||
8855 | EVAS_MEMPOOL_FREE(_mp_obj, o); | ||
8856 | _format_command_shutdown(); | ||
8857 | } | ||
8858 | |||
8859 | |||
8860 | static void | ||
8861 | evas_object_textblock_render(Evas_Object *obj, void *output, void *context, void *surface, int x, int y) | ||
8862 | { | ||
8863 | Evas_Object_Textblock_Paragraph *par, *start = NULL; | ||
8864 | Evas_Object_Textblock_Line *ln; | ||
8865 | Evas_Object_Textblock *o; | ||
8866 | int i, j; | ||
8867 | int cx, cy, cw, ch, clip; | ||
8868 | const char vals[5][5] = | ||
8869 | { | ||
8870 | {0, 1, 2, 1, 0}, | ||
8871 | {1, 3, 4, 3, 1}, | ||
8872 | {2, 4, 5, 4, 2}, | ||
8873 | {1, 3, 4, 3, 1}, | ||
8874 | {0, 1, 2, 1, 0} | ||
8875 | }; | ||
8876 | |||
8877 | /* render object to surface with context, and offxet by x,y */ | ||
8878 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
8879 | obj->layer->evas->engine.func->context_multiplier_unset(output, | ||
8880 | context); | ||
8881 | /* FIXME: This clipping is just until we fix inset handling correctly. */ | ||
8882 | ENFN->context_clip_clip(output, context, | ||
8883 | obj->cur.geometry.x + x, | ||
8884 | obj->cur.geometry.y + y, | ||
8885 | obj->cur.geometry.w, | ||
8886 | obj->cur.geometry.h); | ||
8887 | clip = ENFN->context_clip_get(output, context, &cx, &cy, &cw, &ch); | ||
8888 | /* If there are no paragraphs and thus there are no lines, | ||
8889 | * there's nothing left to do. */ | ||
8890 | if (!o->paragraphs) return; | ||
8891 | |||
8892 | #define ITEM_WALK() \ | ||
8893 | EINA_INLIST_FOREACH(start, par) \ | ||
8894 | { \ | ||
8895 | if (!par->visible) continue; \ | ||
8896 | if (clip) \ | ||
8897 | { \ | ||
8898 | if ((obj->cur.geometry.y + y + par->y + par->h) < (cy - 20)) \ | ||
8899 | continue; \ | ||
8900 | if ((obj->cur.geometry.y + y + par->y) > (cy + ch + 20)) \ | ||
8901 | break; \ | ||
8902 | } \ | ||
8903 | _layout_paragraph_render(o, par); \ | ||
8904 | EINA_INLIST_FOREACH(par->lines, ln) \ | ||
8905 | { \ | ||
8906 | Evas_Object_Textblock_Item *itr; \ | ||
8907 | \ | ||
8908 | if (clip) \ | ||
8909 | { \ | ||
8910 | if ((obj->cur.geometry.y + y + par->y + ln->y + ln->h) < (cy - 20)) \ | ||
8911 | continue; \ | ||
8912 | if ((obj->cur.geometry.y + y + par->y + ln->y) > (cy + ch + 20)) \ | ||
8913 | break; \ | ||
8914 | } \ | ||
8915 | EINA_INLIST_FOREACH(ln->items, itr) \ | ||
8916 | { \ | ||
8917 | Evas_Coord yoff; \ | ||
8918 | yoff = ln->baseline; \ | ||
8919 | if (itr->format->valign != -1.0) \ | ||
8920 | { \ | ||
8921 | yoff += itr->format->valign * (ln->h - itr->h); \ | ||
8922 | } \ | ||
8923 | if (clip) \ | ||
8924 | { \ | ||
8925 | if ((obj->cur.geometry.x + x + ln->x + itr->x + itr->w) < (cx - 20)) \ | ||
8926 | continue; \ | ||
8927 | if ((obj->cur.geometry.x + x + ln->x + itr->x) > (cx + cw + 20)) \ | ||
8928 | break; \ | ||
8929 | } \ | ||
8930 | if ((ln->x + itr->x + itr->w) <= 0) continue; \ | ||
8931 | if (ln->x + itr->x > obj->cur.geometry.w) break; \ | ||
8932 | do | ||
8933 | |||
8934 | #define ITEM_WALK_END() \ | ||
8935 | while (0); \ | ||
8936 | } \ | ||
8937 | } \ | ||
8938 | } \ | ||
8939 | do {} while(0) | ||
8940 | #define COLOR_SET(col) \ | ||
8941 | ENFN->context_color_set(output, context, \ | ||
8942 | (obj->cur.cache.clip.r * ti->parent.format->color.col.r) / 255, \ | ||
8943 | (obj->cur.cache.clip.g * ti->parent.format->color.col.g) / 255, \ | ||
8944 | (obj->cur.cache.clip.b * ti->parent.format->color.col.b) / 255, \ | ||
8945 | (obj->cur.cache.clip.a * ti->parent.format->color.col.a) / 255); | ||
8946 | #define COLOR_SET_AMUL(col, amul) \ | ||
8947 | ENFN->context_color_set(output, context, \ | ||
8948 | (obj->cur.cache.clip.r * ti->parent.format->color.col.r * (amul)) / 65025, \ | ||
8949 | (obj->cur.cache.clip.g * ti->parent.format->color.col.g * (amul)) / 65025, \ | ||
8950 | (obj->cur.cache.clip.b * ti->parent.format->color.col.b * (amul)) / 65025, \ | ||
8951 | (obj->cur.cache.clip.a * ti->parent.format->color.col.a * (amul)) / 65025); | ||
8952 | #define DRAW_TEXT(ox, oy) \ | ||
8953 | if (ti->parent.format->font.font) ENFN->font_draw(output, context, surface, ti->parent.format->font.font, \ | ||
8954 | obj->cur.geometry.x + ln->x + ti->parent.x + x + (ox), \ | ||
8955 | obj->cur.geometry.y + ln->par->y + ln->y + yoff + y + (oy), \ | ||
8956 | ti->parent.w, ti->parent.h, ti->parent.w, ti->parent.h, \ | ||
8957 | &ti->text_props); | ||
8958 | |||
8959 | /* backing */ | ||
8960 | #define DRAW_RECT(ox, oy, ow, oh, or, og, ob, oa) \ | ||
8961 | do \ | ||
8962 | { \ | ||
8963 | ENFN->context_color_set(output, \ | ||
8964 | context, \ | ||
8965 | (obj->cur.cache.clip.r * or) / 255, \ | ||
8966 | (obj->cur.cache.clip.g * og) / 255, \ | ||
8967 | (obj->cur.cache.clip.b * ob) / 255, \ | ||
8968 | (obj->cur.cache.clip.a * oa) / 255); \ | ||
8969 | ENFN->rectangle_draw(output, \ | ||
8970 | context, \ | ||
8971 | surface, \ | ||
8972 | obj->cur.geometry.x + ln->x + x + (ox), \ | ||
8973 | obj->cur.geometry.y + ln->par->y + ln->y + y + (oy), \ | ||
8974 | (ow), \ | ||
8975 | (oh)); \ | ||
8976 | } \ | ||
8977 | while (0) | ||
8978 | |||
8979 | #define DRAW_FORMAT_DASHED(oname, oy, oh, dw, dp) \ | ||
8980 | do \ | ||
8981 | { \ | ||
8982 | if (itr->format->oname) \ | ||
8983 | { \ | ||
8984 | unsigned char _or, _og, _ob, _oa; \ | ||
8985 | int _ind, _dx = 0, _dn, _dr; \ | ||
8986 | _or = itr->format->color.oname.r; \ | ||
8987 | _og = itr->format->color.oname.g; \ | ||
8988 | _ob = itr->format->color.oname.b; \ | ||
8989 | _oa = itr->format->color.oname.a; \ | ||
8990 | if (!EINA_INLIST_GET(itr)->next) \ | ||
8991 | { \ | ||
8992 | _dn = itr->w / (dw + dp); \ | ||
8993 | _dr = itr->w % (dw + dp); \ | ||
8994 | } \ | ||
8995 | else \ | ||
8996 | { \ | ||
8997 | _dn = itr->adv / (dw + dp); \ | ||
8998 | _dr = itr->adv % (dw + dp); \ | ||
8999 | } \ | ||
9000 | if (_dr > dw) _dr = dw; \ | ||
9001 | for (_ind = 0 ; _ind < _dn ; _ind++) \ | ||
9002 | { \ | ||
9003 | DRAW_RECT(itr->x + _dx, oy, dw, oh, _or, _og, _ob, _oa); \ | ||
9004 | _dx += dw + dp; \ | ||
9005 | } \ | ||
9006 | DRAW_RECT(itr->x + _dx, oy, _dr, oh, _or, _og, _ob, _oa); \ | ||
9007 | } \ | ||
9008 | } \ | ||
9009 | while (0) | ||
9010 | |||
9011 | #define DRAW_FORMAT(oname, oy, oh) \ | ||
9012 | do \ | ||
9013 | { \ | ||
9014 | if (itr->format->oname) \ | ||
9015 | { \ | ||
9016 | unsigned char _or, _og, _ob, _oa; \ | ||
9017 | _or = itr->format->color.oname.r; \ | ||
9018 | _og = itr->format->color.oname.g; \ | ||
9019 | _ob = itr->format->color.oname.b; \ | ||
9020 | _oa = itr->format->color.oname.a; \ | ||
9021 | if (!EINA_INLIST_GET(itr)->next) \ | ||
9022 | { \ | ||
9023 | DRAW_RECT(itr->x, oy, itr->w, oh, _or, _og, _ob, _oa); \ | ||
9024 | } \ | ||
9025 | else \ | ||
9026 | { \ | ||
9027 | DRAW_RECT(itr->x, oy, itr->adv, oh, _or, _og, _ob, _oa); \ | ||
9028 | } \ | ||
9029 | } \ | ||
9030 | } \ | ||
9031 | while (0) | ||
9032 | |||
9033 | { | ||
9034 | Evas_Coord look_for_y = 0 - (obj->cur.geometry.y + y); | ||
9035 | if (clip) | ||
9036 | { | ||
9037 | Evas_Coord tmp_lfy = cy - (obj->cur.geometry.y + y); | ||
9038 | if (tmp_lfy > look_for_y) | ||
9039 | look_for_y = tmp_lfy; | ||
9040 | } | ||
9041 | |||
9042 | if (look_for_y >= 0) | ||
9043 | start = _layout_find_paragraph_by_y(o, look_for_y); | ||
9044 | |||
9045 | if (!start) | ||
9046 | start = o->paragraphs; | ||
9047 | } | ||
9048 | |||
9049 | ITEM_WALK() | ||
9050 | { | ||
9051 | DRAW_FORMAT(backing, 0, ln->h); | ||
9052 | } | ||
9053 | ITEM_WALK_END(); | ||
9054 | |||
9055 | /* There are size adjustments that depend on the styles drawn here back | ||
9056 | * in "_text_item_update_sizes" should not modify one without the other. */ | ||
9057 | |||
9058 | /* prepare everything for text draw */ | ||
9059 | |||
9060 | /* shadows */ | ||
9061 | ITEM_WALK() | ||
9062 | { | ||
9063 | int shad_dst, shad_sz, dx, dy, haveshad; | ||
9064 | Evas_Object_Textblock_Text_Item *ti; | ||
9065 | ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL; | ||
9066 | if (!ti) continue; | ||
9067 | |||
9068 | shad_dst = shad_sz = dx = dy = haveshad = 0; | ||
9069 | switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_BASIC) | ||
9070 | { | ||
9071 | case EVAS_TEXT_STYLE_SHADOW: | ||
9072 | case EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW: | ||
9073 | shad_dst = 1; | ||
9074 | haveshad = 1; | ||
9075 | break; | ||
9076 | case EVAS_TEXT_STYLE_OUTLINE_SHADOW: | ||
9077 | case EVAS_TEXT_STYLE_FAR_SHADOW: | ||
9078 | shad_dst = 2; | ||
9079 | haveshad = 1; | ||
9080 | break; | ||
9081 | case EVAS_TEXT_STYLE_FAR_SOFT_SHADOW: | ||
9082 | shad_dst = 2; | ||
9083 | shad_sz = 2; | ||
9084 | haveshad = 1; | ||
9085 | break; | ||
9086 | case EVAS_TEXT_STYLE_SOFT_SHADOW: | ||
9087 | shad_dst = 1; | ||
9088 | shad_sz = 2; | ||
9089 | haveshad = 1; | ||
9090 | break; | ||
9091 | default: | ||
9092 | break; | ||
9093 | } | ||
9094 | if (haveshad) | ||
9095 | { | ||
9096 | if (shad_dst > 0) | ||
9097 | { | ||
9098 | switch (ti->parent.format->style & EVAS_TEXT_STYLE_MASK_SHADOW_DIRECTION) | ||
9099 | { | ||
9100 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT: | ||
9101 | dx = 1; | ||
9102 | dy = 1; | ||
9103 | break; | ||
9104 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM: | ||
9105 | dx = 0; | ||
9106 | dy = 1; | ||
9107 | break; | ||
9108 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT: | ||
9109 | dx = -1; | ||
9110 | dy = 1; | ||
9111 | break; | ||
9112 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT: | ||
9113 | dx = -1; | ||
9114 | dy = 0; | ||
9115 | break; | ||
9116 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT: | ||
9117 | dx = -1; | ||
9118 | dy = -1; | ||
9119 | break; | ||
9120 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP: | ||
9121 | dx = 0; | ||
9122 | dy = -1; | ||
9123 | break; | ||
9124 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT: | ||
9125 | dx = 1; | ||
9126 | dy = -1; | ||
9127 | break; | ||
9128 | case EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT: | ||
9129 | dx = 1; | ||
9130 | dy = 0; | ||
9131 | default: | ||
9132 | break; | ||
9133 | } | ||
9134 | dx *= shad_dst; | ||
9135 | dy *= shad_dst; | ||
9136 | } | ||
9137 | switch (shad_sz) | ||
9138 | { | ||
9139 | case 0: | ||
9140 | COLOR_SET(shadow); | ||
9141 | DRAW_TEXT(dx, dy); | ||
9142 | break; | ||
9143 | case 2: | ||
9144 | for (j = 0; j < 5; j++) | ||
9145 | { | ||
9146 | for (i = 0; i < 5; i++) | ||
9147 | { | ||
9148 | if (vals[i][j] != 0) | ||
9149 | { | ||
9150 | COLOR_SET_AMUL(shadow, vals[i][j] * 50); | ||
9151 | DRAW_TEXT(i - 2 + dx, j - 2 + dy); | ||
9152 | } | ||
9153 | } | ||
9154 | } | ||
9155 | break; | ||
9156 | default: | ||
9157 | break; | ||
9158 | } | ||
9159 | } | ||
9160 | } | ||
9161 | ITEM_WALK_END(); | ||
9162 | |||
9163 | /* glows */ | ||
9164 | ITEM_WALK() | ||
9165 | { | ||
9166 | Evas_Object_Textblock_Text_Item *ti; | ||
9167 | ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL; | ||
9168 | if (!ti) continue; | ||
9169 | |||
9170 | if (ti->parent.format->style == EVAS_TEXT_STYLE_GLOW) | ||
9171 | { | ||
9172 | for (j = 0; j < 5; j++) | ||
9173 | { | ||
9174 | for (i = 0; i < 5; i++) | ||
9175 | { | ||
9176 | if (vals[i][j] != 0) | ||
9177 | { | ||
9178 | COLOR_SET_AMUL(glow, vals[i][j] * 50); | ||
9179 | DRAW_TEXT(i - 2, j - 2); | ||
9180 | } | ||
9181 | } | ||
9182 | } | ||
9183 | COLOR_SET(glow2); | ||
9184 | DRAW_TEXT(-1, 0); | ||
9185 | DRAW_TEXT(1, 0); | ||
9186 | DRAW_TEXT(0, -1); | ||
9187 | DRAW_TEXT(0, 1); | ||
9188 | } | ||
9189 | } | ||
9190 | ITEM_WALK_END(); | ||
9191 | |||
9192 | /* outlines */ | ||
9193 | ITEM_WALK() | ||
9194 | { | ||
9195 | Evas_Object_Textblock_Text_Item *ti; | ||
9196 | ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL; | ||
9197 | if (!ti) continue; | ||
9198 | |||
9199 | if ((ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE) || | ||
9200 | (ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE_SHADOW) || | ||
9201 | (ti->parent.format->style == EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW)) | ||
9202 | { | ||
9203 | COLOR_SET(outline); | ||
9204 | DRAW_TEXT(-1, 0); | ||
9205 | DRAW_TEXT(1, 0); | ||
9206 | DRAW_TEXT(0, -1); | ||
9207 | DRAW_TEXT(0, 1); | ||
9208 | } | ||
9209 | else if (ti->parent.format->style == EVAS_TEXT_STYLE_SOFT_OUTLINE) | ||
9210 | { | ||
9211 | for (j = 0; j < 5; j++) | ||
9212 | { | ||
9213 | for (i = 0; i < 5; i++) | ||
9214 | { | ||
9215 | if (((i != 2) || (j != 2)) && (vals[i][j] != 0)) | ||
9216 | { | ||
9217 | COLOR_SET_AMUL(outline, vals[i][j] * 50); | ||
9218 | DRAW_TEXT(i - 2, j - 2); | ||
9219 | } | ||
9220 | } | ||
9221 | } | ||
9222 | } | ||
9223 | } | ||
9224 | ITEM_WALK_END(); | ||
9225 | |||
9226 | /* normal text and lines */ | ||
9227 | ITEM_WALK() | ||
9228 | { | ||
9229 | Evas_Object_Textblock_Text_Item *ti; | ||
9230 | ti = (itr->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? _ITEM_TEXT(itr) : NULL; | ||
9231 | /* NORMAL TEXT */ | ||
9232 | if (ti) | ||
9233 | { | ||
9234 | COLOR_SET(normal); | ||
9235 | DRAW_TEXT(0, 0); | ||
9236 | } | ||
9237 | |||
9238 | /* STRIKETHROUGH */ | ||
9239 | DRAW_FORMAT(strikethrough, (ln->h / 2), 1); | ||
9240 | |||
9241 | /* UNDERLINE */ | ||
9242 | DRAW_FORMAT(underline, ln->baseline + 1, 1); | ||
9243 | |||
9244 | /* UNDERLINE DASHED */ | ||
9245 | DRAW_FORMAT_DASHED(underline_dash, ln->baseline + 1, 1, | ||
9246 | ti->parent.format->underline_dash_width, | ||
9247 | ti->parent.format->underline_dash_gap); | ||
9248 | |||
9249 | /* UNDERLINE2 */ | ||
9250 | DRAW_FORMAT(underline2, ln->baseline + 3, 1); | ||
9251 | } | ||
9252 | ITEM_WALK_END(); | ||
9253 | } | ||
9254 | |||
9255 | static void | ||
9256 | evas_object_textblock_render_pre(Evas_Object *obj) | ||
9257 | { | ||
9258 | Evas_Object_Textblock *o; | ||
9259 | int is_v, was_v; | ||
9260 | |||
9261 | /* dont pre-render the obj twice! */ | ||
9262 | if (obj->pre_render_done) return; | ||
9263 | obj->pre_render_done = 1; | ||
9264 | /* pre-render phase. this does anything an object needs to do just before */ | ||
9265 | /* rendering. this could mean loading the image data, retrieving it from */ | ||
9266 | /* elsewhere, decoding video etc. */ | ||
9267 | /* then when this is done the object needs to figure if it changed and */ | ||
9268 | /* if so what and where and add the appropriate redraw textblocks */ | ||
9269 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
9270 | if ((o->changed) || (o->content_changed) || (o->format_changed) || | ||
9271 | ((obj->cur.geometry.w != o->last_w) || | ||
9272 | (((o->valign != 0.0) || (o->have_ellipsis)) && | ||
9273 | (obj->cur.geometry.h != o->last_h)))) | ||
9274 | { | ||
9275 | _relayout(obj); | ||
9276 | o->redraw = 0; | ||
9277 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
9278 | is_v = evas_object_is_visible(obj); | ||
9279 | was_v = evas_object_was_visible(obj); | ||
9280 | goto done; | ||
9281 | } | ||
9282 | if (o->redraw) | ||
9283 | { | ||
9284 | o->redraw = 0; | ||
9285 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
9286 | is_v = evas_object_is_visible(obj); | ||
9287 | was_v = evas_object_was_visible(obj); | ||
9288 | goto done; | ||
9289 | } | ||
9290 | /* if someone is clipping this obj - go calculate the clipper */ | ||
9291 | if (obj->cur.clipper) | ||
9292 | { | ||
9293 | if (obj->cur.cache.clip.dirty) | ||
9294 | evas_object_clip_recalc(obj->cur.clipper); | ||
9295 | obj->cur.clipper->func->render_pre(obj->cur.clipper); | ||
9296 | } | ||
9297 | /* now figure what changed and add draw rects */ | ||
9298 | /* if it just became visible or invisible */ | ||
9299 | is_v = evas_object_is_visible(obj); | ||
9300 | was_v = evas_object_was_visible(obj); | ||
9301 | if (is_v != was_v) | ||
9302 | { | ||
9303 | evas_object_render_pre_visible_change(&obj->layer->evas->clip_changes, obj, is_v, was_v); | ||
9304 | goto done; | ||
9305 | } | ||
9306 | if ((obj->cur.map != obj->prev.map) || | ||
9307 | (obj->cur.usemap != obj->prev.usemap)) | ||
9308 | { | ||
9309 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
9310 | goto done; | ||
9311 | } | ||
9312 | /* it's not visible - we accounted for it appearing or not so just abort */ | ||
9313 | if (!is_v) goto done; | ||
9314 | /* clipper changed this is in addition to anything else for obj */ | ||
9315 | evas_object_render_pre_clipper_change(&obj->layer->evas->clip_changes, obj); | ||
9316 | /* if we restacked (layer or just within a layer) and don't clip anyone */ | ||
9317 | if (obj->restack) | ||
9318 | { | ||
9319 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
9320 | goto done; | ||
9321 | } | ||
9322 | /* if it changed color */ | ||
9323 | if ((obj->cur.color.r != obj->prev.color.r) || | ||
9324 | (obj->cur.color.g != obj->prev.color.g) || | ||
9325 | (obj->cur.color.b != obj->prev.color.b) || | ||
9326 | (obj->cur.color.a != obj->prev.color.a)) | ||
9327 | { | ||
9328 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
9329 | goto done; | ||
9330 | } | ||
9331 | /* if it changed geometry - and obviously not visibility or color */ | ||
9332 | /* calculate differences since we have a constant color fill */ | ||
9333 | /* we really only need to update the differences */ | ||
9334 | if ((obj->cur.geometry.x != obj->prev.geometry.x) || | ||
9335 | (obj->cur.geometry.y != obj->prev.geometry.y) || | ||
9336 | (obj->cur.geometry.w != obj->prev.geometry.w) || | ||
9337 | (obj->cur.geometry.h != obj->prev.geometry.h)) | ||
9338 | { | ||
9339 | evas_object_render_pre_prev_cur_add(&obj->layer->evas->clip_changes, obj); | ||
9340 | goto done; | ||
9341 | } | ||
9342 | done: | ||
9343 | evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, obj, is_v, was_v); | ||
9344 | } | ||
9345 | |||
9346 | static void | ||
9347 | evas_object_textblock_render_post(Evas_Object *obj) | ||
9348 | { | ||
9349 | /* Evas_Object_Textblock *o; */ | ||
9350 | |||
9351 | /* this moves the current data to the previous state parts of the object */ | ||
9352 | /* in whatever way is safest for the object. also if we don't need object */ | ||
9353 | /* data anymore we can free it if the object deems this is a good idea */ | ||
9354 | /* o = (Evas_Object_Textblock *)(obj->object_data); */ | ||
9355 | /* remove those pesky changes */ | ||
9356 | evas_object_clip_changes_clean(obj); | ||
9357 | /* move cur to prev safely for object data */ | ||
9358 | obj->prev = obj->cur; | ||
9359 | /* o->prev = o->cur; */ | ||
9360 | /* o->changed = 0; */ | ||
9361 | } | ||
9362 | |||
9363 | static unsigned int evas_object_textblock_id_get(Evas_Object *obj) | ||
9364 | { | ||
9365 | Evas_Object_Textblock *o; | ||
9366 | |||
9367 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
9368 | if (!o) return 0; | ||
9369 | return MAGIC_OBJ_TEXTBLOCK; | ||
9370 | } | ||
9371 | |||
9372 | static unsigned int evas_object_textblock_visual_id_get(Evas_Object *obj) | ||
9373 | { | ||
9374 | Evas_Object_Textblock *o; | ||
9375 | |||
9376 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
9377 | if (!o) return 0; | ||
9378 | return MAGIC_OBJ_CUSTOM; | ||
9379 | } | ||
9380 | |||
9381 | static void *evas_object_textblock_engine_data_get(Evas_Object *obj) | ||
9382 | { | ||
9383 | Evas_Object_Textblock *o; | ||
9384 | |||
9385 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
9386 | if (!o) return NULL; | ||
9387 | return o->engine_data; | ||
9388 | } | ||
9389 | |||
9390 | static int | ||
9391 | evas_object_textblock_is_opaque(Evas_Object *obj __UNUSED__) | ||
9392 | { | ||
9393 | /* this returns 1 if the internal object data implies that the object is */ | ||
9394 | /* currently fulyl opque over the entire gradient it occupies */ | ||
9395 | return 0; | ||
9396 | } | ||
9397 | |||
9398 | static int | ||
9399 | evas_object_textblock_was_opaque(Evas_Object *obj __UNUSED__) | ||
9400 | { | ||
9401 | /* this returns 1 if the internal object data implies that the object was */ | ||
9402 | /* currently fulyl opque over the entire gradient it occupies */ | ||
9403 | return 0; | ||
9404 | } | ||
9405 | |||
9406 | static void | ||
9407 | evas_object_textblock_coords_recalc(Evas_Object *obj) | ||
9408 | { | ||
9409 | Evas_Object_Textblock *o; | ||
9410 | |||
9411 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
9412 | if ((obj->cur.geometry.w != o->last_w) || | ||
9413 | (((o->valign != 0.0) || (o->have_ellipsis)) && | ||
9414 | (obj->cur.geometry.h != o->last_h))) | ||
9415 | { | ||
9416 | o->formatted.valid = 0; | ||
9417 | o->changed = 1; | ||
9418 | } | ||
9419 | } | ||
9420 | |||
9421 | static void | ||
9422 | evas_object_textblock_scale_update(Evas_Object *obj) | ||
9423 | { | ||
9424 | Evas_Object_Textblock *o; | ||
9425 | |||
9426 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
9427 | _evas_textblock_invalidate_all(o); | ||
9428 | _evas_textblock_changed(o, obj); | ||
9429 | } | ||
9430 | |||
9431 | void | ||
9432 | _evas_object_textblock_rehint(Evas_Object *obj) | ||
9433 | { | ||
9434 | Evas_Object_Textblock *o; | ||
9435 | Evas_Object_Textblock_Paragraph *par; | ||
9436 | Evas_Object_Textblock_Line *ln; | ||
9437 | |||
9438 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
9439 | EINA_INLIST_FOREACH(o->paragraphs, par) | ||
9440 | { | ||
9441 | EINA_INLIST_FOREACH(par->lines, ln) | ||
9442 | { | ||
9443 | Evas_Object_Textblock_Item *it; | ||
9444 | |||
9445 | EINA_INLIST_FOREACH(ln->items, it) | ||
9446 | { | ||
9447 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
9448 | { | ||
9449 | Evas_Object_Textblock_Text_Item *ti = _ITEM_TEXT(it); | ||
9450 | if (ti->parent.format->font.font) | ||
9451 | { | ||
9452 | #ifdef EVAS_FRAME_QUEUING | ||
9453 | evas_common_pipe_op_text_flush((RGBA_Font *) ti->parent.format->font.font); | ||
9454 | #endif | ||
9455 | evas_font_load_hinting_set(obj->layer->evas, | ||
9456 | ti->parent.format->font.font, | ||
9457 | obj->layer->evas->hinting); | ||
9458 | } | ||
9459 | } | ||
9460 | } | ||
9461 | } | ||
9462 | } | ||
9463 | _evas_textblock_invalidate_all(o); | ||
9464 | _evas_textblock_changed(o, obj); | ||
9465 | } | ||
9466 | |||
9467 | /** | ||
9468 | * @} | ||
9469 | */ | ||
9470 | |||
9471 | #ifdef HAVE_TESTS | ||
9472 | /* return EINA_FALSE on error, used in unit_testing */ | ||
9473 | EAPI Eina_Bool | ||
9474 | _evas_textblock_check_item_node_link(Evas_Object *obj) | ||
9475 | { | ||
9476 | Evas_Object_Textblock *o; | ||
9477 | Evas_Object_Textblock_Paragraph *par; | ||
9478 | Evas_Object_Textblock_Line *ln; | ||
9479 | Evas_Object_Textblock_Item *it; | ||
9480 | |||
9481 | o = (Evas_Object_Textblock *)(obj->object_data); | ||
9482 | if (!o) return EINA_FALSE; | ||
9483 | |||
9484 | if (!o->formatted.valid) _relayout(obj); | ||
9485 | |||
9486 | EINA_INLIST_FOREACH(o->paragraphs, par) | ||
9487 | { | ||
9488 | EINA_INLIST_FOREACH(par->lines, ln) | ||
9489 | { | ||
9490 | EINA_INLIST_FOREACH(ln->items, it) | ||
9491 | { | ||
9492 | if (it->text_node != par->text_node) | ||
9493 | return EINA_FALSE; | ||
9494 | } | ||
9495 | } | ||
9496 | } | ||
9497 | return EINA_TRUE; | ||
9498 | } | ||
9499 | |||
9500 | EAPI int | ||
9501 | _evas_textblock_format_offset_get(const Evas_Object_Textblock_Node_Format *n) | ||
9502 | { | ||
9503 | return n->offset; | ||
9504 | } | ||
9505 | #endif | ||
9506 | |||
9507 | #if 0 | ||
9508 | /* Good for debugging */ | ||
9509 | void | ||
9510 | pfnode(Evas_Object_Textblock_Node_Format *n) | ||
9511 | { | ||
9512 | printf("Format Node: %p\n", n); | ||
9513 | printf("next = %p, prev = %p, last = %p\n", EINA_INLIST_GET(n)->next, EINA_INLIST_GET(n)->prev, EINA_INLIST_GET(n)->last); | ||
9514 | printf("text_node = %p, offset = %u, visible = %d\n", n->text_node, n->offset, n->visible); | ||
9515 | printf("'%s'\n", eina_strbuf_string_get(n->format)); | ||
9516 | } | ||
9517 | |||
9518 | void | ||
9519 | ptnode(Evas_Object_Textblock_Node_Text *n) | ||
9520 | { | ||
9521 | printf("Text Node: %p\n", n); | ||
9522 | printf("next = %p, prev = %p, last = %p\n", EINA_INLIST_GET(n)->next, EINA_INLIST_GET(n)->prev, EINA_INLIST_GET(n)->last); | ||
9523 | printf("format_node = %p\n", n->format_node); | ||
9524 | printf("'%ls'\n", eina_ustrbuf_string_get(n->unicode)); | ||
9525 | } | ||
9526 | |||
9527 | void | ||
9528 | pitem(Evas_Object_Textblock_Item *it) | ||
9529 | { | ||
9530 | Evas_Object_Textblock_Text_Item *ti; | ||
9531 | Evas_Object_Textblock_Format_Item *fi; | ||
9532 | printf("Item: %p\n", it); | ||
9533 | printf("Type: %s (%d)\n", (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) ? | ||
9534 | "TEXT" : "FORMAT", it->type); | ||
9535 | printf("Text pos: %d Visual pos: %d\n", it->text_pos, | ||
9536 | #ifdef BIDI_SUPPORT | ||
9537 | it->visual_pos | ||
9538 | #else | ||
9539 | it->text_pos | ||
9540 | #endif | ||
9541 | ); | ||
9542 | printf("Coords: x = %d w = %d adv = %d\n", (int) it->x, (int) it->w, | ||
9543 | (int) it->adv); | ||
9544 | if (it->type == EVAS_TEXTBLOCK_ITEM_TEXT) | ||
9545 | { | ||
9546 | ti = _ITEM_TEXT(it); | ||
9547 | printf("Text: '%*ls'\n", ti->text_props.text_len, GET_ITEM_TEXT(ti)); | ||
9548 | } | ||
9549 | else | ||
9550 | { | ||
9551 | fi = _ITEM_FORMAT(it); | ||
9552 | printf("Format: '%s'\n", fi->item); | ||
9553 | } | ||
9554 | } | ||
9555 | |||
9556 | void | ||
9557 | ppar(Evas_Object_Textblock_Paragraph *par) | ||
9558 | { | ||
9559 | Evas_Object_Textblock_Item *it; | ||
9560 | Eina_List *i; | ||
9561 | EINA_LIST_FOREACH(par->logical_items, i, it) | ||
9562 | { | ||
9563 | printf("***********************\n"); | ||
9564 | pitem(it); | ||
9565 | } | ||
9566 | } | ||
9567 | |||
9568 | #endif | ||
9569 | |||
diff --git a/libraries/evas/src/lib/canvas/evas_rectangle.c b/libraries/evas/src/lib/canvas/evas_rectangle.c new file mode 100644 index 0000000..da6b701 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_rectangle.c | |||
@@ -0,0 +1,98 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | void | ||
5 | evas_rects_return_difference_rects(Eina_Array *rects, int x, int y, int w, int h, int xx, int yy, int ww, int hh) | ||
6 | { | ||
7 | if (!RECTS_INTERSECT(x, y, w, h, xx, yy, ww, hh)) | ||
8 | { | ||
9 | evas_add_rect(rects, x, y, w, h); | ||
10 | evas_add_rect(rects, xx, yy, ww, hh); | ||
11 | } | ||
12 | else | ||
13 | { | ||
14 | int pt_x[4], pt_y[4], i, j; | ||
15 | |||
16 | if (x < xx) | ||
17 | { | ||
18 | pt_x[0] = x; | ||
19 | pt_x[1] = xx; | ||
20 | } | ||
21 | else | ||
22 | { | ||
23 | pt_x[0] = xx; | ||
24 | pt_x[1] = x; | ||
25 | } | ||
26 | if ((x + w) < (xx + ww)) | ||
27 | { | ||
28 | pt_x[2] = x + w; | ||
29 | pt_x[3] = xx + ww; | ||
30 | } | ||
31 | else | ||
32 | { | ||
33 | pt_x[2] = xx + ww; | ||
34 | pt_x[3] = x + w; | ||
35 | } | ||
36 | if (y < yy) | ||
37 | { | ||
38 | pt_y[0] = y; | ||
39 | pt_y[1] = yy; | ||
40 | } | ||
41 | else | ||
42 | { | ||
43 | pt_y[0] = yy; | ||
44 | pt_y[1] = y; | ||
45 | } | ||
46 | if ((y + h) < (yy + hh)) | ||
47 | { | ||
48 | pt_y[2] = y + h; | ||
49 | pt_y[3] = yy + hh; | ||
50 | } | ||
51 | else | ||
52 | { | ||
53 | pt_y[2] = yy + hh; | ||
54 | pt_y[3] = y + h; | ||
55 | } | ||
56 | for (j = 0; j < 3; j++) | ||
57 | { | ||
58 | for (i = 0; i < 3; i++) | ||
59 | { | ||
60 | int intsec1, intsec2; | ||
61 | int tx, ty, tw, th; | ||
62 | |||
63 | tx = pt_x[i]; | ||
64 | ty = pt_y[j]; | ||
65 | tw = pt_x[i + 1] - pt_x[i]; | ||
66 | th = pt_y[j + 1] - pt_y[j]; | ||
67 | |||
68 | intsec1 = (RECTS_INTERSECT(tx, ty, tw, th, x, y, w, h)); | ||
69 | intsec2 = (RECTS_INTERSECT(tx, ty, tw, th, xx, yy, ww, hh)); | ||
70 | if (intsec1 ^ intsec2) | ||
71 | { | ||
72 | evas_add_rect(rects, tx, ty, tw, th); | ||
73 | } | ||
74 | } | ||
75 | } | ||
76 | /* if (tmp.count > 0) */ | ||
77 | /* { */ | ||
78 | /* unsigned int i; */ | ||
79 | |||
80 | /* for (i = 0; i < tmp.count; ++i) */ | ||
81 | /* { */ | ||
82 | /* if ((tmp.array[i].w > 0) && (tmp.array[i].h > 0)) */ | ||
83 | /* { */ | ||
84 | /* int intsec1, intsec2; */ | ||
85 | |||
86 | /* intsec1 = (RECTS_INTERSECT(tmp.array[i].x, tmp.array[i].y, tmp.array[i].w, tmp.array[i].h, x, y, w, h)); */ | ||
87 | /* intsec2 = (RECTS_INTERSECT(tmp.array[i].x, tmp.array[i].y, tmp.array[i].w, tmp.array[i].h, xx, yy, ww, hh)); */ | ||
88 | /* if (intsec1 ^ intsec2) */ | ||
89 | /* { */ | ||
90 | /* evas_add_rect(rects, tmp.array[i].x, tmp.array[i].y, tmp.array[i].w, tmp.array[i].h); */ | ||
91 | /* } */ | ||
92 | /* } */ | ||
93 | /* } */ | ||
94 | /* free(tmp.array); */ | ||
95 | /* } */ | ||
96 | |||
97 | } | ||
98 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_render.c b/libraries/evas/src/lib/canvas/evas_render.c new file mode 100644 index 0000000..0abee97 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_render.c | |||
@@ -0,0 +1,1866 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | #include <math.h> | ||
4 | |||
5 | // debug rendering | ||
6 | /* #define REND_DGB 1 */ | ||
7 | /* #define STDOUT_DBG 1 */ | ||
8 | |||
9 | #ifdef REND_DGB | ||
10 | static FILE *dbf = NULL; | ||
11 | |||
12 | static void | ||
13 | rend_dbg(const char *txt) | ||
14 | { | ||
15 | if (!dbf) | ||
16 | { | ||
17 | #ifdef STDOUT_DBG | ||
18 | dbf = stdout; | ||
19 | #else | ||
20 | dbf = fopen("EVAS-RENDER-DEBUG.log", "w"); | ||
21 | #endif | ||
22 | if (!dbf) return; | ||
23 | } | ||
24 | fputs(txt, dbf); | ||
25 | fflush(dbf); | ||
26 | } | ||
27 | #define RD(args...) \ | ||
28 | { \ | ||
29 | char __tmpbuf[4096]; \ | ||
30 | \ | ||
31 | snprintf(__tmpbuf, sizeof(__tmpbuf), ##args); \ | ||
32 | rend_dbg(__tmpbuf); \ | ||
33 | } | ||
34 | #define RDI(xxxx) \ | ||
35 | { \ | ||
36 | char __tmpbuf[4096]; int __tmpi; \ | ||
37 | for (__tmpi = 0; __tmpi < xxxx; __tmpi++) \ | ||
38 | __tmpbuf[__tmpi] = ' '; \ | ||
39 | __tmpbuf[__tmpi] = 0; \ | ||
40 | rend_dbg(__tmpbuf); \ | ||
41 | } | ||
42 | #else | ||
43 | #define RD(args...) | ||
44 | #define RDI(x) | ||
45 | #endif | ||
46 | |||
47 | static Eina_List * | ||
48 | evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char do_draw); | ||
49 | |||
50 | EAPI void | ||
51 | evas_damage_rectangle_add(Evas *e, int x, int y, int w, int h) | ||
52 | { | ||
53 | Eina_Rectangle *r; | ||
54 | |||
55 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
56 | return; | ||
57 | MAGIC_CHECK_END(); | ||
58 | NEW_RECT(r, x, y, w, h); | ||
59 | if (!r) return; | ||
60 | e->damages = eina_list_append(e->damages, r); | ||
61 | e->changed = 1; | ||
62 | } | ||
63 | |||
64 | EAPI void | ||
65 | evas_obscured_rectangle_add(Evas *e, int x, int y, int w, int h) | ||
66 | { | ||
67 | Eina_Rectangle *r; | ||
68 | |||
69 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
70 | return; | ||
71 | MAGIC_CHECK_END(); | ||
72 | NEW_RECT(r, x, y, w, h); | ||
73 | if (!r) return; | ||
74 | e->obscures = eina_list_append(e->obscures, r); | ||
75 | } | ||
76 | |||
77 | EAPI void | ||
78 | evas_obscured_clear(Evas *e) | ||
79 | { | ||
80 | Eina_Rectangle *r; | ||
81 | |||
82 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
83 | return; | ||
84 | MAGIC_CHECK_END(); | ||
85 | EINA_LIST_FREE(e->obscures, r) | ||
86 | { | ||
87 | eina_rectangle_free(r); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static Eina_Bool | ||
92 | _evas_render_has_map(Evas_Object *obj) | ||
93 | { | ||
94 | return ((!((obj->func->can_map) && (obj->func->can_map(obj)))) && | ||
95 | ((obj->cur.map) && (obj->cur.usemap))); | ||
96 | // return ((obj->cur.map) && (obj->cur.usemap)); | ||
97 | } | ||
98 | |||
99 | static Eina_Bool | ||
100 | _evas_render_had_map(Evas_Object *obj) | ||
101 | { | ||
102 | return ((obj->prev.map) && (obj->prev.usemap)); | ||
103 | // return ((!obj->cur.map) && (obj->prev.usemap)); | ||
104 | } | ||
105 | |||
106 | static Eina_Bool | ||
107 | _evas_render_is_relevant(Evas_Object *obj) | ||
108 | { | ||
109 | return ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) || | ||
110 | (evas_object_was_visible(obj) && (!obj->prev.have_clipees))); | ||
111 | } | ||
112 | |||
113 | static Eina_Bool | ||
114 | _evas_render_can_render(Evas_Object *obj) | ||
115 | { | ||
116 | return (evas_object_is_visible(obj) && (!obj->cur.have_clipees)); | ||
117 | } | ||
118 | |||
119 | static void | ||
120 | _evas_render_prev_cur_clip_cache_add(Evas *e, Evas_Object *obj) | ||
121 | { | ||
122 | e->engine.func->output_redraws_rect_add(e->engine.data.output, | ||
123 | obj->prev.cache.clip.x, | ||
124 | obj->prev.cache.clip.y, | ||
125 | obj->prev.cache.clip.w, | ||
126 | obj->prev.cache.clip.h); | ||
127 | e->engine.func->output_redraws_rect_add(e->engine.data.output, | ||
128 | obj->cur.cache.clip.x, | ||
129 | obj->cur.cache.clip.y, | ||
130 | obj->cur.cache.clip.w, | ||
131 | obj->cur.cache.clip.h); | ||
132 | } | ||
133 | |||
134 | static void | ||
135 | _evas_render_cur_clip_cache_del(Evas *e, Evas_Object *obj) | ||
136 | { | ||
137 | Evas_Coord x, y, w, h; | ||
138 | |||
139 | x = obj->cur.cache.clip.x; | ||
140 | y = obj->cur.cache.clip.y; | ||
141 | w = obj->cur.cache.clip.w; | ||
142 | h = obj->cur.cache.clip.h; | ||
143 | if (obj->cur.clipper) | ||
144 | { | ||
145 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
146 | obj->cur.clipper->cur.cache.clip.x, | ||
147 | obj->cur.clipper->cur.cache.clip.y, | ||
148 | obj->cur.clipper->cur.cache.clip.w, | ||
149 | obj->cur.clipper->cur.cache.clip.h); | ||
150 | } | ||
151 | e->engine.func->output_redraws_rect_del(e->engine.data.output, | ||
152 | x, y, w, h); | ||
153 | } | ||
154 | |||
155 | static void | ||
156 | _evas_render_phase1_direct(Evas *e, | ||
157 | Eina_Array *active_objects, | ||
158 | Eina_Array *restack_objects __UNUSED__, | ||
159 | Eina_Array *delete_objects __UNUSED__, | ||
160 | Eina_Array *render_objects) | ||
161 | { | ||
162 | unsigned int i; | ||
163 | Eina_List *l; | ||
164 | Evas_Object *proxy; | ||
165 | |||
166 | RD(" [--- PHASE 1 DIRECT\n"); | ||
167 | for (i = 0; i < active_objects->count; i++) | ||
168 | { | ||
169 | Evas_Object *obj; | ||
170 | |||
171 | obj = eina_array_data_get(active_objects, i); | ||
172 | if (obj->changed) | ||
173 | { | ||
174 | /* Flag need redraw on proxy too */ | ||
175 | evas_object_clip_recalc(obj); | ||
176 | if (obj->proxy.proxies) | ||
177 | { | ||
178 | EINA_LIST_FOREACH(obj->proxy.proxies, l, proxy) | ||
179 | proxy->proxy.redraw = 1; | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | for (i = 0; i < render_objects->count; i++) | ||
184 | { | ||
185 | Evas_Object *obj; | ||
186 | |||
187 | obj = eina_array_data_get(render_objects, i); | ||
188 | RD(" OBJ [%p] changed %i\n", obj, obj->changed); | ||
189 | if (obj->changed) | ||
190 | { | ||
191 | /* Flag need redraw on proxy too */ | ||
192 | evas_object_clip_recalc(obj); | ||
193 | obj->func->render_pre(obj); | ||
194 | if (obj->proxy.proxies) | ||
195 | { | ||
196 | obj->proxy.redraw = 1; | ||
197 | EINA_LIST_FOREACH(obj->proxy.proxies, l, proxy) | ||
198 | { | ||
199 | proxy->func->render_pre(proxy); | ||
200 | _evas_render_prev_cur_clip_cache_add(e, proxy); | ||
201 | } | ||
202 | } | ||
203 | else if (obj->proxy.redraw) | ||
204 | { | ||
205 | _evas_render_prev_cur_clip_cache_add(e, obj); | ||
206 | } | ||
207 | if (obj->pre_render_done) | ||
208 | { | ||
209 | RD(" pre-render-done smart:%p|%p [%p, %i] | [%p, %i] has_map:%i had_map:%i\n", | ||
210 | obj->smart.smart, | ||
211 | evas_object_smart_members_get_direct(obj), | ||
212 | obj->cur.map, obj->cur.usemap, | ||
213 | obj->prev.map, obj->prev.usemap, | ||
214 | _evas_render_has_map(obj), | ||
215 | _evas_render_had_map(obj)); | ||
216 | if ((obj->smart.smart) && | ||
217 | (_evas_render_has_map(obj))) | ||
218 | { | ||
219 | RD(" has map + smart\n"); | ||
220 | _evas_render_prev_cur_clip_cache_add(e, obj); | ||
221 | } | ||
222 | } | ||
223 | else if (_evas_render_had_map(obj)) | ||
224 | { | ||
225 | RD(" no pre-render done\n"); | ||
226 | _evas_render_prev_cur_clip_cache_add(e, obj); | ||
227 | } | ||
228 | } | ||
229 | else | ||
230 | { | ||
231 | if (obj->smart.smart) | ||
232 | { | ||
233 | // obj->func->render_pre(obj); | ||
234 | } | ||
235 | else if ((obj->rect_del) || | ||
236 | (evas_object_is_opaque(obj) && evas_object_is_visible(obj))) | ||
237 | { | ||
238 | RD(" rect del\n"); | ||
239 | _evas_render_cur_clip_cache_del(e, obj); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | RD(" ---]\n"); | ||
244 | } | ||
245 | |||
246 | static Eina_Bool | ||
247 | _evas_render_phase1_object_process(Evas *e, Evas_Object *obj, | ||
248 | Eina_Array *active_objects, | ||
249 | Eina_Array *restack_objects, | ||
250 | Eina_Array *delete_objects, | ||
251 | Eina_Array *render_objects, | ||
252 | int restack, int map, | ||
253 | int *redraw_all | ||
254 | #ifdef REND_DGB | ||
255 | , int level | ||
256 | #endif | ||
257 | ) | ||
258 | { | ||
259 | Eina_Bool clean_them = EINA_FALSE; | ||
260 | Evas_Object *obj2; | ||
261 | int is_active; | ||
262 | Eina_Bool hmap; | ||
263 | |||
264 | obj->rect_del = 0; | ||
265 | obj->render_pre = 0; | ||
266 | |||
267 | #ifndef EVAS_FRAME_QUEUING | ||
268 | /* because of clip objects - delete 2 cycles later */ | ||
269 | if (obj->delete_me == 2) | ||
270 | #else | ||
271 | if (obj->delete_me == evas_common_frameq_get_frameq_sz() + 2) | ||
272 | #endif | ||
273 | eina_array_push(delete_objects, obj); | ||
274 | else if (obj->delete_me != 0) obj->delete_me++; | ||
275 | /* If the object will be removed, we should not cache anything during this run. */ | ||
276 | if (obj->delete_me != 0) clean_them = EINA_TRUE; | ||
277 | |||
278 | /* build active object list */ | ||
279 | evas_object_clip_recalc(obj); | ||
280 | is_active = evas_object_is_active(obj); | ||
281 | obj->is_active = is_active; | ||
282 | |||
283 | RDI(level); | ||
284 | RD(" [--- PROCESS [%p] '%s' active = %i, del = %i | %i %i %ix%i\n", obj, obj->type, is_active, obj->delete_me, obj->cur.geometry.x, obj->cur.geometry.y, obj->cur.geometry.w, obj->cur.geometry.h); | ||
285 | if ((is_active) || (obj->delete_me != 0)) | ||
286 | eina_array_push(active_objects, obj); | ||
287 | |||
288 | #ifdef REND_DGB | ||
289 | if (!is_active) | ||
290 | { | ||
291 | RDI(level); | ||
292 | RD(" [%p] vis: %i, cache.clip.vis: %i cache.clip.a: %i [%p]\n", obj, obj->cur.visible, obj->cur.cache.clip.visible, obj->cur.cache.clip.a, obj->func->is_visible); | ||
293 | } | ||
294 | #endif | ||
295 | |||
296 | map = _evas_render_has_map(obj); | ||
297 | hmap = _evas_render_had_map(obj); | ||
298 | |||
299 | if ((restack) && (!map)) | ||
300 | { | ||
301 | if (!obj->changed) | ||
302 | { | ||
303 | eina_array_push(&e->pending_objects, obj); | ||
304 | obj->changed = 1; | ||
305 | } | ||
306 | obj->restack = 1; | ||
307 | clean_them = EINA_TRUE; | ||
308 | } | ||
309 | |||
310 | if (map) | ||
311 | { | ||
312 | RDI(level); | ||
313 | RD(" obj mapped\n"); | ||
314 | if (obj->changed) | ||
315 | { | ||
316 | if (map != hmap) | ||
317 | { | ||
318 | *redraw_all = 1; | ||
319 | } | ||
320 | evas_object_clip_recalc(obj); | ||
321 | if ((obj->restack) && | ||
322 | (is_active) && (!obj->clip.clipees) && | ||
323 | ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) || | ||
324 | (evas_object_was_visible(obj) && (!obj->prev.have_clipees)))) | ||
325 | { | ||
326 | eina_array_push(render_objects, obj); | ||
327 | _evas_render_prev_cur_clip_cache_add(e, obj); | ||
328 | obj->render_pre = 1; | ||
329 | } | ||
330 | else if ((is_active) && (!obj->clip.clipees) && | ||
331 | ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) || | ||
332 | (evas_object_was_visible(obj) && (!obj->prev.have_clipees)))) | ||
333 | { | ||
334 | eina_array_push(render_objects, obj); | ||
335 | _evas_render_prev_cur_clip_cache_add(e, obj); | ||
336 | obj->render_pre = 1; | ||
337 | } | ||
338 | } | ||
339 | return clean_them; | ||
340 | } | ||
341 | else if (_evas_render_had_map(obj)) | ||
342 | { | ||
343 | RDI(level); | ||
344 | RD(" had map - restack objs\n"); | ||
345 | // eina_array_push(restack_objects, obj); | ||
346 | _evas_render_prev_cur_clip_cache_add(e, obj); | ||
347 | if (obj->changed) | ||
348 | { | ||
349 | if (hmap) | ||
350 | { | ||
351 | if (!map) | ||
352 | { | ||
353 | if ((obj->cur.map) && (obj->cur.usemap)) map = 1; | ||
354 | } | ||
355 | } | ||
356 | if (map != hmap) | ||
357 | { | ||
358 | *redraw_all = 1; | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | |||
363 | /* handle normal rendering. this object knows how to handle maps */ | ||
364 | if (obj->changed) | ||
365 | { | ||
366 | if (obj->smart.smart) | ||
367 | { | ||
368 | RDI(level); | ||
369 | RD(" changed + smart - render ok\n"); | ||
370 | eina_array_push(render_objects, obj); | ||
371 | obj->render_pre = 1; | ||
372 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2) | ||
373 | { | ||
374 | _evas_render_phase1_object_process(e, obj2, | ||
375 | active_objects, | ||
376 | restack_objects, | ||
377 | delete_objects, | ||
378 | render_objects, | ||
379 | obj->restack, | ||
380 | map, | ||
381 | redraw_all | ||
382 | #ifdef REND_DGB | ||
383 | , level + 1 | ||
384 | #endif | ||
385 | ); | ||
386 | } | ||
387 | } | ||
388 | else | ||
389 | { | ||
390 | if ((is_active) && (!obj->clip.clipees) && | ||
391 | _evas_render_is_relevant(obj)) | ||
392 | { | ||
393 | RDI(level); | ||
394 | RD(" relevant + active\n"); | ||
395 | if (obj->restack) | ||
396 | eina_array_push(restack_objects, obj); | ||
397 | else | ||
398 | { | ||
399 | eina_array_push(render_objects, obj); | ||
400 | obj->render_pre = 1; | ||
401 | } | ||
402 | } | ||
403 | else | ||
404 | { | ||
405 | RDI(level); | ||
406 | RD(" skip - not smart, not active or clippees or not relevant\n"); | ||
407 | } | ||
408 | } | ||
409 | } | ||
410 | else | ||
411 | { | ||
412 | RD(" not changed... [%i] -> (%i %i %p %i) [%i]\n", | ||
413 | evas_object_is_visible(obj), | ||
414 | obj->cur.visible, obj->cur.cache.clip.visible, obj->smart.smart, obj->cur.cache.clip.a, | ||
415 | evas_object_was_visible(obj)); | ||
416 | if ((!obj->clip.clipees) && (obj->delete_me == 0) && | ||
417 | (_evas_render_can_render(obj) || | ||
418 | (evas_object_was_visible(obj) && (!obj->prev.have_clipees)))) | ||
419 | { | ||
420 | if (obj->smart.smart) | ||
421 | { | ||
422 | RDI(level); | ||
423 | RD(" smart + visible/was visible + not clip\n"); | ||
424 | eina_array_push(render_objects, obj); | ||
425 | obj->render_pre = 1; | ||
426 | EINA_INLIST_FOREACH | ||
427 | (evas_object_smart_members_get_direct(obj), obj2) | ||
428 | { | ||
429 | _evas_render_phase1_object_process(e, obj2, | ||
430 | active_objects, | ||
431 | restack_objects, | ||
432 | delete_objects, | ||
433 | render_objects, | ||
434 | restack, map, | ||
435 | redraw_all | ||
436 | #ifdef REND_DGB | ||
437 | , level + 1 | ||
438 | #endif | ||
439 | ); | ||
440 | } | ||
441 | } | ||
442 | else | ||
443 | { | ||
444 | if (evas_object_is_opaque(obj) && | ||
445 | evas_object_is_visible(obj)) | ||
446 | { | ||
447 | RDI(level); | ||
448 | RD(" opaque + visible\n"); | ||
449 | eina_array_push(render_objects, obj); | ||
450 | obj->rect_del = 1; | ||
451 | } | ||
452 | else if (evas_object_is_visible(obj)) | ||
453 | { | ||
454 | RDI(level); | ||
455 | RD(" visible\n"); | ||
456 | eina_array_push(render_objects, obj); | ||
457 | obj->render_pre = 1; | ||
458 | } | ||
459 | else | ||
460 | { | ||
461 | RDI(level); | ||
462 | RD(" skip\n"); | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | /* | ||
467 | else if (obj->smart.smart) | ||
468 | { | ||
469 | RDI(level); | ||
470 | RD(" smart + mot visible/was visible\n"); | ||
471 | eina_array_push(render_objects, obj); | ||
472 | obj->render_pre = 1; | ||
473 | EINA_INLIST_FOREACH | ||
474 | (evas_object_smart_members_get_direct(obj), obj2) | ||
475 | { | ||
476 | _evas_render_phase1_object_process(e, obj2, | ||
477 | active_objects, | ||
478 | restack_objects, | ||
479 | delete_objects, | ||
480 | render_objects, | ||
481 | restack, map, | ||
482 | redraw_all | ||
483 | #ifdef REND_DGB | ||
484 | , level + 1 | ||
485 | #endif | ||
486 | ); | ||
487 | } | ||
488 | } | ||
489 | */ | ||
490 | } | ||
491 | if (!is_active) obj->restack = 0; | ||
492 | RDI(level); | ||
493 | RD(" ---]\n"); | ||
494 | return clean_them; | ||
495 | } | ||
496 | |||
497 | static Eina_Bool | ||
498 | _evas_render_phase1_process(Evas *e, | ||
499 | Eina_Array *active_objects, | ||
500 | Eina_Array *restack_objects, | ||
501 | Eina_Array *delete_objects, | ||
502 | Eina_Array *render_objects, | ||
503 | int *redraw_all) | ||
504 | { | ||
505 | Evas_Layer *lay; | ||
506 | Eina_Bool clean_them = EINA_FALSE; | ||
507 | |||
508 | RD(" [--- PHASE 1\n"); | ||
509 | EINA_INLIST_FOREACH(e->layers, lay) | ||
510 | { | ||
511 | Evas_Object *obj; | ||
512 | |||
513 | EINA_INLIST_FOREACH(lay->objects, obj) | ||
514 | { | ||
515 | clean_them |= _evas_render_phase1_object_process | ||
516 | (e, obj, active_objects, restack_objects, delete_objects, | ||
517 | render_objects, 0, 0, redraw_all | ||
518 | #ifdef REND_DGB | ||
519 | , 1 | ||
520 | #endif | ||
521 | ); | ||
522 | } | ||
523 | } | ||
524 | RD(" ---]\n"); | ||
525 | return clean_them; | ||
526 | } | ||
527 | |||
528 | static void | ||
529 | _evas_render_check_pending_objects(Eina_Array *pending_objects, Evas *e) | ||
530 | { | ||
531 | unsigned int i; | ||
532 | |||
533 | for (i = 0; i < pending_objects->count; ++i) | ||
534 | { | ||
535 | Evas_Object *obj; | ||
536 | int is_active, ok = 0; | ||
537 | |||
538 | obj = eina_array_data_get(pending_objects, i); | ||
539 | |||
540 | if (!obj->layer) goto clean_stuff; | ||
541 | |||
542 | evas_object_clip_recalc(obj); | ||
543 | is_active = evas_object_is_active(obj); | ||
544 | |||
545 | if ((!is_active) && (!obj->is_active) && (!obj->render_pre) && | ||
546 | (!obj->rect_del)) | ||
547 | { | ||
548 | ok = 1; | ||
549 | goto clean_stuff; | ||
550 | } | ||
551 | |||
552 | if (obj->is_active == is_active) | ||
553 | { | ||
554 | if (obj->changed) | ||
555 | { | ||
556 | if (obj->smart.smart) | ||
557 | { | ||
558 | if (obj->render_pre || obj->rect_del) ok = 1; | ||
559 | } | ||
560 | else | ||
561 | if ((is_active) && (obj->restack) && (!obj->clip.clipees) && | ||
562 | (_evas_render_can_render(obj) || | ||
563 | (evas_object_was_visible(obj) && (!obj->prev.have_clipees)))) | ||
564 | { | ||
565 | if (!(obj->render_pre || obj->rect_del)) ok = 1; | ||
566 | } | ||
567 | else | ||
568 | if (is_active && (!obj->clip.clipees) && | ||
569 | (_evas_render_can_render(obj) || | ||
570 | (evas_object_was_visible(obj) && (!obj->prev.have_clipees)))) | ||
571 | { | ||
572 | if (obj->render_pre || obj->rect_del) ok = 1; | ||
573 | } | ||
574 | } | ||
575 | else | ||
576 | { | ||
577 | if ((!obj->clip.clipees) && (obj->delete_me == 0) && | ||
578 | (!obj->cur.have_clipees || (evas_object_was_visible(obj) && (!obj->prev.have_clipees))) | ||
579 | && evas_object_is_opaque(obj) && evas_object_is_visible(obj)) | ||
580 | { | ||
581 | if (obj->rect_del || obj->smart.smart) ok = 1; | ||
582 | } | ||
583 | } | ||
584 | } | ||
585 | |||
586 | clean_stuff: | ||
587 | if (!ok) | ||
588 | { | ||
589 | eina_array_clean(&e->active_objects); | ||
590 | eina_array_clean(&e->render_objects); | ||
591 | eina_array_clean(&e->restack_objects); | ||
592 | eina_array_clean(&e->delete_objects); | ||
593 | e->invalidate = 1; | ||
594 | return ; | ||
595 | } | ||
596 | } | ||
597 | } | ||
598 | |||
599 | Eina_Bool | ||
600 | pending_change(void *data, void *gdata __UNUSED__) | ||
601 | { | ||
602 | Evas_Object *obj; | ||
603 | |||
604 | obj = data; | ||
605 | if (obj->delete_me) return EINA_FALSE; | ||
606 | if (obj->pre_render_done) | ||
607 | { | ||
608 | RD(" OBJ [%p] pending change %i -> 0, pre %i\n", obj, obj->changed, obj->pre_render_done); | ||
609 | obj->pre_render_done = 0; | ||
610 | //// FIXME: this wipes out changes | ||
611 | obj->changed = 0; | ||
612 | obj->changed_move_only = 0; | ||
613 | obj->changed_nomove = 0; | ||
614 | obj->changed_move = 0; | ||
615 | } | ||
616 | return obj->changed ? EINA_TRUE : EINA_FALSE; | ||
617 | } | ||
618 | /* | ||
619 | static void | ||
620 | unchange(Evas_Object *obj) | ||
621 | { | ||
622 | Evas_Object *obj2; | ||
623 | |||
624 | if (!obj->changed) return; | ||
625 | obj->changed = 0; | ||
626 | obj->changed_move_only = 0; | ||
627 | obj->changed_nomove = 0; | ||
628 | obj->changed_move = 0; | ||
629 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2) | ||
630 | { | ||
631 | unchange(obj2); | ||
632 | } | ||
633 | } | ||
634 | |||
635 | static int | ||
636 | chlist(Evas_Object *obj, int i) | ||
637 | { | ||
638 | Evas_Object *obj2; | ||
639 | int j; | ||
640 | int ret = 0; | ||
641 | |||
642 | if (!obj->changed) return 0; | ||
643 | for (j = 0; j < i; j++) printf(" "); | ||
644 | printf("ch2 %p %s %i [%i %i %ix%i] v %i/%i [r%i] %p\n", obj, | ||
645 | obj->type, | ||
646 | obj->changed_move_only, | ||
647 | obj->cur.geometry.x, | ||
648 | obj->cur.geometry.y, | ||
649 | obj->cur.geometry.w, | ||
650 | obj->cur.geometry.h, | ||
651 | obj->cur.visible, | ||
652 | obj->prev.visible, | ||
653 | obj->restack, | ||
654 | obj->clip.clipees); | ||
655 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2) | ||
656 | { | ||
657 | if (obj2->changed) | ||
658 | ret |= chlist(obj2, i + 1); | ||
659 | } | ||
660 | } | ||
661 | */ | ||
662 | static Eina_Bool | ||
663 | _evas_render_can_use_overlay(Evas *e, Evas_Object *obj) | ||
664 | { | ||
665 | Eina_Rectangle *r; | ||
666 | Evas_Object *tmp; | ||
667 | Eina_List *alphas = NULL; | ||
668 | Eina_List *opaques = NULL; | ||
669 | Evas_Object *video_parent = NULL; | ||
670 | Eina_Rectangle zone; | ||
671 | Evas_Coord xc1, yc1, xc2, yc2; | ||
672 | unsigned int i; | ||
673 | Eina_Bool nooverlay; | ||
674 | |||
675 | video_parent = _evas_object_image_video_parent_get(obj); | ||
676 | |||
677 | /* Check if any one is the stack make this object mapped */ | ||
678 | tmp = obj; | ||
679 | while (tmp && !_evas_render_has_map(tmp)) | ||
680 | tmp = tmp->smart.parent; | ||
681 | |||
682 | if (tmp && _evas_render_has_map(tmp)) return EINA_FALSE; /* we are mapped, we can't be an overlay */ | ||
683 | |||
684 | if (!evas_object_is_visible(obj)) return EINA_FALSE; /* no need to update the overlay if it's not visible */ | ||
685 | |||
686 | /* If any recoloring of the surface is needed, n overlay to */ | ||
687 | if ((obj->cur.cache.clip.r != 255) || | ||
688 | (obj->cur.cache.clip.g != 255) || | ||
689 | (obj->cur.cache.clip.b != 255) || | ||
690 | (obj->cur.cache.clip.a != 255)) | ||
691 | return EINA_FALSE; | ||
692 | |||
693 | /* Check presence of transparent object on top of the video object */ | ||
694 | EINA_RECTANGLE_SET(&zone, | ||
695 | obj->cur.cache.clip.x, | ||
696 | obj->cur.cache.clip.y, | ||
697 | obj->cur.cache.clip.w, | ||
698 | obj->cur.cache.clip.h); | ||
699 | |||
700 | for (i = e->active_objects.count - 1; i > 0; i--) | ||
701 | { | ||
702 | Eina_Rectangle self; | ||
703 | Eina_Rectangle *match; | ||
704 | Evas_Object *current; | ||
705 | Eina_List *l; | ||
706 | int xm1, ym1, xm2, ym2; | ||
707 | |||
708 | current = eina_array_data_get(&e->active_objects, i); | ||
709 | |||
710 | /* Did we find the video object in the stack ? */ | ||
711 | if (current == video_parent || current == obj) | ||
712 | break; | ||
713 | |||
714 | EINA_RECTANGLE_SET(&self, | ||
715 | current->cur.cache.clip.x, | ||
716 | current->cur.cache.clip.y, | ||
717 | current->cur.cache.clip.w, | ||
718 | current->cur.cache.clip.h); | ||
719 | |||
720 | /* This doesn't cover the area of the video object, so don't bother with that object */ | ||
721 | if (!eina_rectangles_intersect(&zone, &self)) | ||
722 | continue ; | ||
723 | |||
724 | xc1 = current->cur.cache.clip.x; | ||
725 | yc1 = current->cur.cache.clip.y; | ||
726 | xc2 = current->cur.cache.clip.x + current->cur.cache.clip.w; | ||
727 | yc2 = current->cur.cache.clip.y + current->cur.cache.clip.h; | ||
728 | |||
729 | if (evas_object_is_visible(current) && | ||
730 | (!current->clip.clipees) && | ||
731 | (current->cur.visible) && | ||
732 | (!current->delete_me) && | ||
733 | (current->cur.cache.clip.visible) && | ||
734 | (!current->smart.smart)) | ||
735 | { | ||
736 | Eina_Bool included = EINA_FALSE; | ||
737 | |||
738 | if (evas_object_is_opaque(current) || | ||
739 | ((current->func->has_opaque_rect) && | ||
740 | (current->func->has_opaque_rect(current)))) | ||
741 | { | ||
742 | /* The object is opaque */ | ||
743 | |||
744 | /* Check if the opaque object is inside another opaque object */ | ||
745 | EINA_LIST_FOREACH(opaques, l, match) | ||
746 | { | ||
747 | xm1 = match->x; | ||
748 | ym1 = match->y; | ||
749 | xm2 = match->x + match->w; | ||
750 | ym2 = match->y + match->h; | ||
751 | |||
752 | /* Both object are included */ | ||
753 | if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2) | ||
754 | { | ||
755 | included = EINA_TRUE; | ||
756 | break; | ||
757 | } | ||
758 | } | ||
759 | |||
760 | /* Not included yet */ | ||
761 | if (!included) | ||
762 | { | ||
763 | Eina_List *ln; | ||
764 | Evas_Coord xn2, yn2; | ||
765 | |||
766 | r = eina_rectangle_new(current->cur.cache.clip.x, current->cur.cache.clip.y, | ||
767 | current->cur.cache.clip.w, current->cur.cache.clip.h); | ||
768 | |||
769 | opaques = eina_list_append(opaques, r); | ||
770 | |||
771 | xn2 = r->x + r->w; | ||
772 | yn2 = r->y + r->h; | ||
773 | |||
774 | /* Remove all the transparent object that are covered by the new opaque object */ | ||
775 | EINA_LIST_FOREACH_SAFE(alphas, l, ln, match) | ||
776 | { | ||
777 | xm1 = match->x; | ||
778 | ym1 = match->y; | ||
779 | xm2 = match->x + match->w; | ||
780 | ym2 = match->y + match->h; | ||
781 | |||
782 | if (xm1 >= r->x && ym1 >= r->y && xm2 <= xn2 && ym2 <= yn2) | ||
783 | { | ||
784 | /* The new rectangle is over some transparent object, | ||
785 | so remove the transparent object */ | ||
786 | alphas = eina_list_remove_list(alphas, l); | ||
787 | } | ||
788 | } | ||
789 | } | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | /* The object has some transparency */ | ||
794 | |||
795 | /* Check if the transparent object is inside any other transparent object */ | ||
796 | EINA_LIST_FOREACH(alphas, l, match) | ||
797 | { | ||
798 | xm1 = match->x; | ||
799 | ym1 = match->y; | ||
800 | xm2 = match->x + match->w; | ||
801 | ym2 = match->y + match->h; | ||
802 | |||
803 | /* Both object are included */ | ||
804 | if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2) | ||
805 | { | ||
806 | included = EINA_TRUE; | ||
807 | break; | ||
808 | } | ||
809 | } | ||
810 | |||
811 | /* If not check if it is inside any opaque one */ | ||
812 | if (!included) | ||
813 | { | ||
814 | EINA_LIST_FOREACH(opaques, l, match) | ||
815 | { | ||
816 | xm1 = match->x; | ||
817 | ym1 = match->y; | ||
818 | xm2 = match->x + match->w; | ||
819 | ym2 = match->y + match->h; | ||
820 | |||
821 | /* Both object are included */ | ||
822 | if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2) | ||
823 | { | ||
824 | included = EINA_TRUE; | ||
825 | break; | ||
826 | } | ||
827 | } | ||
828 | } | ||
829 | |||
830 | /* No inclusion at all, so add it */ | ||
831 | if (!included) | ||
832 | { | ||
833 | r = eina_rectangle_new(current->cur.cache.clip.x, current->cur.cache.clip.y, | ||
834 | current->cur.cache.clip.w, current->cur.cache.clip.h); | ||
835 | |||
836 | alphas = eina_list_append(alphas, r); | ||
837 | } | ||
838 | } | ||
839 | } | ||
840 | } | ||
841 | |||
842 | /* If there is any pending transparent object, then no overlay */ | ||
843 | nooverlay = !!eina_list_count(alphas); | ||
844 | |||
845 | EINA_LIST_FREE(alphas, r) | ||
846 | eina_rectangle_free(r); | ||
847 | EINA_LIST_FREE(opaques, r) | ||
848 | eina_rectangle_free(r); | ||
849 | |||
850 | if (nooverlay) | ||
851 | return EINA_FALSE; | ||
852 | |||
853 | return EINA_TRUE; | ||
854 | } | ||
855 | |||
856 | Eina_Bool | ||
857 | evas_render_mapped(Evas *e, Evas_Object *obj, void *context, void *surface, | ||
858 | int off_x, int off_y, int mapped, | ||
859 | int ecx, int ecy, int ecw, int ech | ||
860 | #ifdef REND_DGB | ||
861 | , int level | ||
862 | #endif | ||
863 | ) | ||
864 | { | ||
865 | void *ctx; | ||
866 | Evas_Object *obj2; | ||
867 | Eina_Bool clean_them = EINA_FALSE; | ||
868 | |||
869 | evas_object_clip_recalc(obj); | ||
870 | RDI(level); | ||
871 | RD(" { evas_render_mapped(%p, %p, %p, %p, %i, %i, %i, %i)\n", e, obj, context, surface, off_x, off_y, mapped, level); | ||
872 | if (mapped) | ||
873 | { | ||
874 | if ((!evas_object_is_visible(obj)) || (obj->clip.clipees) || | ||
875 | (obj->cur.have_clipees)) | ||
876 | { | ||
877 | RDI(level); | ||
878 | RD(" }\n"); | ||
879 | return clean_them; | ||
880 | } | ||
881 | } | ||
882 | else if (!(((evas_object_is_active(obj) && (!obj->clip.clipees) && | ||
883 | (_evas_render_can_render(obj)))) | ||
884 | )) | ||
885 | { | ||
886 | RDI(level); | ||
887 | RD(" }\n"); | ||
888 | return clean_them; | ||
889 | } | ||
890 | |||
891 | // set render_pre - for child objs that may not have gotten it. | ||
892 | obj->pre_render_done = 1; | ||
893 | RD(" Hasmap: %p (%d) %p %d -> %d\n",obj->func->can_map, | ||
894 | obj->func->can_map ? obj->func->can_map(obj): -1, | ||
895 | obj->cur.map, obj->cur.usemap, | ||
896 | _evas_render_has_map(obj)); | ||
897 | if (_evas_render_has_map(obj)) | ||
898 | { | ||
899 | const Evas_Map_Point *p, *p_end; | ||
900 | RGBA_Map_Point pts[4], *pt; | ||
901 | int sw, sh; | ||
902 | int changed = 0, rendered = 0; | ||
903 | |||
904 | clean_them = EINA_TRUE; | ||
905 | |||
906 | sw = obj->cur.geometry.w; | ||
907 | sh = obj->cur.geometry.h; | ||
908 | RDI(level); | ||
909 | RD(" mapped obj: %ix%i\n", sw, sh); | ||
910 | if ((sw <= 0) || (sh <= 0)) | ||
911 | { | ||
912 | RDI(level); | ||
913 | RD(" }\n"); | ||
914 | return clean_them; | ||
915 | } | ||
916 | |||
917 | pts[0].px = obj->cur.map->persp.px << FP; | ||
918 | pts[0].py = obj->cur.map->persp.py << FP; | ||
919 | pts[0].foc = obj->cur.map->persp.foc << FP; | ||
920 | pts[0].z0 = obj->cur.map->persp.z0 << FP; | ||
921 | |||
922 | p = obj->cur.map->points; | ||
923 | p_end = p + obj->cur.map->count; | ||
924 | pt = pts; | ||
925 | for (; p < p_end; p++, pt++) | ||
926 | { | ||
927 | pt->x = (lround(p->x) + off_x) * FP1; | ||
928 | pt->y = (lround(p->y) + off_y) * FP1; | ||
929 | pt->z = (lround(p->z) ) * FP1; | ||
930 | pt->fx = p->px; | ||
931 | pt->fy = p->py; | ||
932 | pt->fz = p->z; | ||
933 | pt->u = lround(p->u) * FP1; | ||
934 | pt->v = lround(p->v) * FP1; | ||
935 | if (pt->u < 0) pt->u = 0; | ||
936 | else if (pt->u > (sw * FP1)) pt->u = (sw * FP1); | ||
937 | if (pt->v < 0) pt->v = 0; | ||
938 | else if (pt->v > (sh * FP1)) pt->v = (sh * FP1); | ||
939 | pt->col = ARGB_JOIN(p->a, p->r, p->g, p->b); | ||
940 | } | ||
941 | /* Copy last for software engine */ | ||
942 | if (obj->cur.map->count & 0x1) | ||
943 | { | ||
944 | pts[obj->cur.map->count] = pts[obj->cur.map->count - 1]; | ||
945 | } | ||
946 | |||
947 | |||
948 | if (obj->cur.map->surface) | ||
949 | { | ||
950 | if ((obj->cur.map->surface_w != sw) || | ||
951 | (obj->cur.map->surface_h != sh)) | ||
952 | { | ||
953 | RDI(level); | ||
954 | RD(" new surf: %ix%i\n", sw, sh); | ||
955 | obj->layer->evas->engine.func->image_map_surface_free | ||
956 | (e->engine.data.output, obj->cur.map->surface); | ||
957 | obj->cur.map->surface = NULL; | ||
958 | } | ||
959 | } | ||
960 | if (!obj->cur.map->surface) | ||
961 | { | ||
962 | obj->cur.map->surface_w = sw; | ||
963 | obj->cur.map->surface_h = sh; | ||
964 | |||
965 | obj->cur.map->surface = | ||
966 | obj->layer->evas->engine.func->image_map_surface_new | ||
967 | (e->engine.data.output, obj->cur.map->surface_w, | ||
968 | obj->cur.map->surface_h, | ||
969 | obj->cur.map->alpha); | ||
970 | RDI(level); | ||
971 | RD(" fisrt surf: %ix%i\n", sw, sh); | ||
972 | changed = 1; | ||
973 | } | ||
974 | if (obj->smart.smart) | ||
975 | { | ||
976 | Evas_Object *o2; | ||
977 | |||
978 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), o2) | ||
979 | { | ||
980 | if (!evas_object_is_visible(o2) && | ||
981 | !evas_object_was_visible(o2)) | ||
982 | { | ||
983 | o2->changed = 0; | ||
984 | o2->changed_move_only = 0; | ||
985 | o2->changed_nomove = 0; | ||
986 | o2->changed_move = 0; | ||
987 | continue; | ||
988 | } | ||
989 | if (o2->changed) | ||
990 | { | ||
991 | // chlist(o2, 0); | ||
992 | changed = 1; | ||
993 | o2->changed = 0; | ||
994 | o2->changed_move_only = 0; | ||
995 | o2->changed_nomove = 0; | ||
996 | o2->changed_move = 0; | ||
997 | break; | ||
998 | } | ||
999 | } | ||
1000 | // unchange(obj); | ||
1001 | obj->changed = 0; | ||
1002 | obj->changed_move_only = 0; | ||
1003 | obj->changed_nomove = 0; | ||
1004 | obj->changed_move = 0; | ||
1005 | } | ||
1006 | else | ||
1007 | { | ||
1008 | if (obj->changed) | ||
1009 | { | ||
1010 | changed = 1; | ||
1011 | obj->changed = 0; | ||
1012 | obj->changed_move_only = 0; | ||
1013 | obj->changed_nomove = 0; | ||
1014 | obj->changed_move = 0; | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | // clear surface before re-render | ||
1019 | if ((changed) && (obj->cur.map->surface)) | ||
1020 | { | ||
1021 | int off_x2, off_y2; | ||
1022 | |||
1023 | RDI(level); | ||
1024 | RD(" children redraw\n"); | ||
1025 | // FIXME: calculate "changes" within map surface and only clear | ||
1026 | // and re-render those | ||
1027 | if (obj->cur.map->alpha) | ||
1028 | { | ||
1029 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
1030 | e->engine.func->context_color_set | ||
1031 | (e->engine.data.output, ctx, 0, 0, 0, 0); | ||
1032 | e->engine.func->context_render_op_set | ||
1033 | (e->engine.data.output, ctx, EVAS_RENDER_COPY); | ||
1034 | e->engine.func->rectangle_draw(e->engine.data.output, | ||
1035 | ctx, | ||
1036 | obj->cur.map->surface, | ||
1037 | 0, 0, | ||
1038 | obj->cur.map->surface_w, | ||
1039 | obj->cur.map->surface_h); | ||
1040 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
1041 | } | ||
1042 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
1043 | off_x2 = -obj->cur.geometry.x; | ||
1044 | off_y2 = -obj->cur.geometry.y; | ||
1045 | if (obj->smart.smart) | ||
1046 | { | ||
1047 | EINA_INLIST_FOREACH | ||
1048 | (evas_object_smart_members_get_direct(obj), obj2) | ||
1049 | { | ||
1050 | clean_them |= evas_render_mapped(e, obj2, ctx, | ||
1051 | obj->cur.map->surface, | ||
1052 | off_x2, off_y2, 1, | ||
1053 | ecx, ecy, ecw, ech | ||
1054 | #ifdef REND_DGB | ||
1055 | , level + 1 | ||
1056 | #endif | ||
1057 | ); | ||
1058 | } | ||
1059 | } | ||
1060 | else | ||
1061 | { | ||
1062 | int x = 0, y = 0, w = 0, h = 0; | ||
1063 | |||
1064 | w = obj->cur.map->surface_w; | ||
1065 | h = obj->cur.map->surface_h; | ||
1066 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
1067 | obj->cur.geometry.x + off_x2, | ||
1068 | obj->cur.geometry.y + off_y2, | ||
1069 | obj->cur.geometry.w, | ||
1070 | obj->cur.geometry.h); | ||
1071 | |||
1072 | e->engine.func->context_clip_set(e->engine.data.output, | ||
1073 | ctx, x, y, w, h); | ||
1074 | obj->func->render(obj, e->engine.data.output, ctx, | ||
1075 | obj->cur.map->surface, off_x2, off_y2); | ||
1076 | } | ||
1077 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
1078 | rendered = 1; | ||
1079 | } | ||
1080 | |||
1081 | RDI(level); | ||
1082 | RD(" draw map\n"); | ||
1083 | |||
1084 | if (rendered) | ||
1085 | { | ||
1086 | obj->cur.map->surface = e->engine.func->image_dirty_region | ||
1087 | (e->engine.data.output, obj->cur.map->surface, | ||
1088 | 0, 0, obj->cur.map->surface_w, obj->cur.map->surface_h); | ||
1089 | } | ||
1090 | e->engine.func->context_clip_unset(e->engine.data.output, | ||
1091 | e->engine.data.context); | ||
1092 | if (obj->cur.map->surface) | ||
1093 | { | ||
1094 | if (obj->smart.smart) | ||
1095 | { | ||
1096 | if (obj->cur.clipper) | ||
1097 | { | ||
1098 | int x, y, w, h; | ||
1099 | Evas_Object *tobj; | ||
1100 | |||
1101 | obj->cur.cache.clip.dirty = 1; | ||
1102 | tobj = obj->cur.map_parent; | ||
1103 | obj->cur.map_parent = obj->cur.clipper->cur.map_parent; | ||
1104 | evas_object_clip_recalc(obj); | ||
1105 | obj->cur.map_parent = tobj; | ||
1106 | x = obj->cur.cache.clip.x; | ||
1107 | y = obj->cur.cache.clip.y; | ||
1108 | w = obj->cur.cache.clip.w; | ||
1109 | h = obj->cur.cache.clip.h; | ||
1110 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
1111 | obj->cur.clipper->cur.cache.clip.x, | ||
1112 | obj->cur.clipper->cur.cache.clip.y, | ||
1113 | obj->cur.clipper->cur.cache.clip.w, | ||
1114 | obj->cur.clipper->cur.cache.clip.h); | ||
1115 | e->engine.func->context_clip_set(e->engine.data.output, | ||
1116 | e->engine.data.context, | ||
1117 | x + off_x, y + off_y, w, h); | ||
1118 | } | ||
1119 | } | ||
1120 | else | ||
1121 | { | ||
1122 | if (obj->cur.clipper) | ||
1123 | { | ||
1124 | int x, y, w, h; | ||
1125 | |||
1126 | evas_object_clip_recalc(obj); | ||
1127 | x = obj->cur.cache.clip.x; | ||
1128 | y = obj->cur.cache.clip.y; | ||
1129 | w = obj->cur.cache.clip.w; | ||
1130 | h = obj->cur.cache.clip.h; | ||
1131 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
1132 | obj->cur.clipper->cur.cache.clip.x, | ||
1133 | obj->cur.clipper->cur.cache.clip.y, | ||
1134 | obj->cur.clipper->cur.cache.clip.w, | ||
1135 | obj->cur.clipper->cur.cache.clip.h); | ||
1136 | e->engine.func->context_clip_set(e->engine.data.output, | ||
1137 | e->engine.data.context, | ||
1138 | x + off_x, y + off_y, w, h); | ||
1139 | } | ||
1140 | } | ||
1141 | } | ||
1142 | if (surface == e->engine.data.output) | ||
1143 | e->engine.func->context_clip_clip(e->engine.data.output, | ||
1144 | e->engine.data.context, | ||
1145 | ecx, ecy, ecw, ech); | ||
1146 | if (obj->cur.cache.clip.visible) | ||
1147 | obj->layer->evas->engine.func->image_map_draw | ||
1148 | (e->engine.data.output, e->engine.data.context, surface, | ||
1149 | obj->cur.map->surface, obj->cur.map->count, pts, | ||
1150 | obj->cur.map->smooth, 0); | ||
1151 | // FIXME: needs to cache these maps and | ||
1152 | // keep them only rendering updates | ||
1153 | // obj->layer->evas->engine.func->image_map_surface_free | ||
1154 | // (e->engine.data.output, obj->cur.map->surface); | ||
1155 | // obj->cur.map->surface = NULL; | ||
1156 | } | ||
1157 | else | ||
1158 | { | ||
1159 | if (mapped) | ||
1160 | { | ||
1161 | RDI(level); | ||
1162 | RD(" draw child of mapped obj\n"); | ||
1163 | ctx = e->engine.func->context_new(e->engine.data.output); | ||
1164 | if (obj->smart.smart) | ||
1165 | { | ||
1166 | EINA_INLIST_FOREACH | ||
1167 | (evas_object_smart_members_get_direct(obj), obj2) | ||
1168 | { | ||
1169 | clean_them |= evas_render_mapped(e, obj2, ctx, | ||
1170 | surface, | ||
1171 | off_x, off_y, 1, | ||
1172 | ecx, ecy, ecw, ech | ||
1173 | #ifdef REND_DGB | ||
1174 | , level + 1 | ||
1175 | #endif | ||
1176 | ); | ||
1177 | } | ||
1178 | } | ||
1179 | else | ||
1180 | { | ||
1181 | if (!obj->cur.map) | ||
1182 | { | ||
1183 | int x, y, w, h; | ||
1184 | |||
1185 | RDI(level); | ||
1186 | |||
1187 | x = obj->cur.cache.clip.x + off_x; | ||
1188 | y = obj->cur.cache.clip.y + off_y; | ||
1189 | w = obj->cur.cache.clip.w; | ||
1190 | h = obj->cur.cache.clip.h; | ||
1191 | |||
1192 | if (obj->cur.clipper) | ||
1193 | { | ||
1194 | if (_evas_render_has_map(obj)) | ||
1195 | evas_object_clip_recalc(obj); | ||
1196 | |||
1197 | RD(" clipper: %i %i %ix%i\n", | ||
1198 | obj->cur.clipper->cur.cache.clip.x + off_x, | ||
1199 | obj->cur.clipper->cur.cache.clip.y + off_y, | ||
1200 | obj->cur.clipper->cur.cache.clip.w, | ||
1201 | obj->cur.clipper->cur.cache.clip.h); | ||
1202 | |||
1203 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
1204 | obj->cur.clipper->cur.cache.clip.x + off_x, | ||
1205 | obj->cur.clipper->cur.cache.clip.y + off_y, | ||
1206 | obj->cur.clipper->cur.cache.clip.w, | ||
1207 | obj->cur.clipper->cur.cache.clip.h); | ||
1208 | } | ||
1209 | |||
1210 | RD(" clip: %i %i %ix%i [%i %i %ix%i]\n", | ||
1211 | obj->cur.cache.clip.x + off_x, | ||
1212 | obj->cur.cache.clip.y + off_y, | ||
1213 | obj->cur.cache.clip.w, | ||
1214 | obj->cur.cache.clip.h, | ||
1215 | obj->cur.geometry.x + off_x, | ||
1216 | obj->cur.geometry.y + off_y, | ||
1217 | obj->cur.geometry.w, | ||
1218 | obj->cur.geometry.h); | ||
1219 | e->engine.func->context_clip_set(e->engine.data.output, | ||
1220 | ctx, x, y, w, h); | ||
1221 | } | ||
1222 | else | ||
1223 | { | ||
1224 | RDI(level); | ||
1225 | RD(" noclip\n"); | ||
1226 | } | ||
1227 | obj->func->render(obj, e->engine.data.output, ctx, | ||
1228 | surface, off_x, off_y); | ||
1229 | /* | ||
1230 | obj->layer->evas->engine.func->context_color_set(e->engine.data.output, | ||
1231 | ctx, | ||
1232 | 0, 30, 0, 30); | ||
1233 | obj->layer->evas->engine.func->rectangle_draw(e->engine.data.output, | ||
1234 | ctx, | ||
1235 | surface, | ||
1236 | 0, 0, 9999, 9999); | ||
1237 | */ | ||
1238 | } | ||
1239 | e->engine.func->context_free(e->engine.data.output, ctx); | ||
1240 | } | ||
1241 | else | ||
1242 | { | ||
1243 | if (obj->cur.clipper) | ||
1244 | { | ||
1245 | int x, y, w, h; | ||
1246 | |||
1247 | if (_evas_render_has_map(obj)) | ||
1248 | evas_object_clip_recalc(obj); | ||
1249 | x = obj->cur.cache.clip.x; | ||
1250 | y = obj->cur.cache.clip.y; | ||
1251 | w = obj->cur.cache.clip.w; | ||
1252 | h = obj->cur.cache.clip.h; | ||
1253 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
1254 | obj->cur.clipper->cur.cache.clip.x, | ||
1255 | obj->cur.clipper->cur.cache.clip.y, | ||
1256 | obj->cur.clipper->cur.cache.clip.w, | ||
1257 | obj->cur.clipper->cur.cache.clip.h); | ||
1258 | e->engine.func->context_clip_set(e->engine.data.output, | ||
1259 | e->engine.data.context, | ||
1260 | x + off_x, y + off_y, w, h); | ||
1261 | e->engine.func->context_clip_clip(e->engine.data.output, | ||
1262 | e->engine.data.context, | ||
1263 | ecx, ecy, ecw, ech); | ||
1264 | } | ||
1265 | |||
1266 | RDI(level); | ||
1267 | RD(" draw normal obj\n"); | ||
1268 | obj->func->render(obj, e->engine.data.output, context, surface, | ||
1269 | off_x, off_y); | ||
1270 | } | ||
1271 | } | ||
1272 | RDI(level); | ||
1273 | RD(" }\n"); | ||
1274 | |||
1275 | return clean_them; | ||
1276 | } | ||
1277 | |||
1278 | static void | ||
1279 | _evas_render_cutout_add(Evas *e, Evas_Object *obj, int off_x, int off_y) | ||
1280 | { | ||
1281 | if (evas_object_is_opaque(obj)) | ||
1282 | { | ||
1283 | Evas_Coord cox, coy, cow, coh; | ||
1284 | |||
1285 | cox = obj->cur.cache.clip.x; | ||
1286 | coy = obj->cur.cache.clip.y; | ||
1287 | cow = obj->cur.cache.clip.w; | ||
1288 | coh = obj->cur.cache.clip.h; | ||
1289 | if ((obj->cur.map) && (obj->cur.usemap)) | ||
1290 | { | ||
1291 | Evas_Object *oo; | ||
1292 | |||
1293 | oo = obj; | ||
1294 | while (oo->cur.clipper) | ||
1295 | { | ||
1296 | if ((oo->cur.clipper->cur.map_parent | ||
1297 | != oo->cur.map_parent) && | ||
1298 | (!((oo->cur.map) && (oo->cur.usemap)))) | ||
1299 | break; | ||
1300 | RECTS_CLIP_TO_RECT(cox, coy, cow, coh, | ||
1301 | oo->cur.geometry.x, | ||
1302 | oo->cur.geometry.y, | ||
1303 | oo->cur.geometry.w, | ||
1304 | oo->cur.geometry.h); | ||
1305 | oo = oo->cur.clipper; | ||
1306 | } | ||
1307 | } | ||
1308 | e->engine.func->context_cutout_add | ||
1309 | (e->engine.data.output, e->engine.data.context, | ||
1310 | cox + off_x, coy + off_y, cow, coh); | ||
1311 | } | ||
1312 | else | ||
1313 | { | ||
1314 | if (obj->func->get_opaque_rect) | ||
1315 | { | ||
1316 | Evas_Coord obx, oby, obw, obh; | ||
1317 | |||
1318 | obj->func->get_opaque_rect(obj, &obx, &oby, &obw, &obh); | ||
1319 | if ((obw > 0) && (obh > 0)) | ||
1320 | { | ||
1321 | obx += off_x; | ||
1322 | oby += off_y; | ||
1323 | RECTS_CLIP_TO_RECT(obx, oby, obw, obh, | ||
1324 | obj->cur.cache.clip.x + off_x, | ||
1325 | obj->cur.cache.clip.y + off_y, | ||
1326 | obj->cur.cache.clip.w, | ||
1327 | obj->cur.cache.clip.h); | ||
1328 | e->engine.func->context_cutout_add | ||
1329 | (e->engine.data.output, e->engine.data.context, | ||
1330 | obx, oby, obw, obh); | ||
1331 | } | ||
1332 | } | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | static Eina_List * | ||
1337 | evas_render_updates_internal(Evas *e, | ||
1338 | unsigned char make_updates, | ||
1339 | unsigned char do_draw) | ||
1340 | { | ||
1341 | Evas_Object *obj; | ||
1342 | Eina_List *updates = NULL; | ||
1343 | Eina_List *ll; | ||
1344 | void *surface; | ||
1345 | Eina_Bool clean_them = EINA_FALSE; | ||
1346 | Eina_Bool alpha; | ||
1347 | Eina_Rectangle *r; | ||
1348 | int ux, uy, uw, uh; | ||
1349 | int cx, cy, cw, ch; | ||
1350 | unsigned int i, j; | ||
1351 | int haveup = 0; | ||
1352 | int redraw_all = 0; | ||
1353 | |||
1354 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1355 | return NULL; | ||
1356 | MAGIC_CHECK_END(); | ||
1357 | if (!e->changed) return NULL; | ||
1358 | |||
1359 | evas_call_smarts_calculate(e); | ||
1360 | |||
1361 | RD("[--- RENDER EVAS (size: %ix%i)\n", e->viewport.w, e->viewport.h); | ||
1362 | |||
1363 | /* Check if the modified object mean recalculating every thing */ | ||
1364 | if (!e->invalidate) | ||
1365 | _evas_render_check_pending_objects(&e->pending_objects, e); | ||
1366 | |||
1367 | /* phase 1. add extra updates for changed objects */ | ||
1368 | if (e->invalidate || e->render_objects.count <= 0) | ||
1369 | clean_them = _evas_render_phase1_process(e, | ||
1370 | &e->active_objects, | ||
1371 | &e->restack_objects, | ||
1372 | &e->delete_objects, | ||
1373 | &e->render_objects, | ||
1374 | &redraw_all); | ||
1375 | |||
1376 | /* phase 1.5. check if the video should be inlined or stay in their overlay */ | ||
1377 | alpha = e->engine.func->canvas_alpha_get(e->engine.data.output, | ||
1378 | e->engine.data.context); | ||
1379 | |||
1380 | EINA_LIST_FOREACH(e->video_objects, ll, obj) | ||
1381 | { | ||
1382 | /* we need the surface to be transparent to display the underlying overlay */ | ||
1383 | if (alpha && _evas_render_can_use_overlay(e, obj)) | ||
1384 | _evas_object_image_video_overlay_show(obj); | ||
1385 | else | ||
1386 | _evas_object_image_video_overlay_hide(obj); | ||
1387 | } | ||
1388 | |||
1389 | |||
1390 | /* phase 1.8. pre render for proxy */ | ||
1391 | _evas_render_phase1_direct(e, &e->active_objects, &e->restack_objects, | ||
1392 | &e->delete_objects, &e->render_objects); | ||
1393 | |||
1394 | /* phase 2. force updates for restacks */ | ||
1395 | for (i = 0; i < e->restack_objects.count; ++i) | ||
1396 | { | ||
1397 | obj = eina_array_data_get(&e->restack_objects, i); | ||
1398 | obj->func->render_pre(obj); | ||
1399 | _evas_render_prev_cur_clip_cache_add(e, obj); | ||
1400 | } | ||
1401 | eina_array_clean(&e->restack_objects); | ||
1402 | /* phase 3. add exposes */ | ||
1403 | EINA_LIST_FREE(e->damages, r) | ||
1404 | { | ||
1405 | e->engine.func->output_redraws_rect_add(e->engine.data.output, | ||
1406 | r->x, r->y, r->w, r->h); | ||
1407 | eina_rectangle_free(r); | ||
1408 | } | ||
1409 | /* phase 4. output & viewport changes */ | ||
1410 | if (e->viewport.changed) | ||
1411 | { | ||
1412 | e->engine.func->output_redraws_rect_add(e->engine.data.output, | ||
1413 | 0, 0, | ||
1414 | e->output.w, e->output.h); | ||
1415 | } | ||
1416 | if (e->output.changed) | ||
1417 | { | ||
1418 | e->engine.func->output_resize(e->engine.data.output, | ||
1419 | e->output.w, e->output.h); | ||
1420 | e->engine.func->output_redraws_rect_add(e->engine.data.output, | ||
1421 | 0, 0, | ||
1422 | e->output.w, e->output.h); | ||
1423 | } | ||
1424 | if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h)) | ||
1425 | { | ||
1426 | ERR("viewport size != output size!"); | ||
1427 | } | ||
1428 | if (redraw_all) | ||
1429 | { | ||
1430 | e->engine.func->output_redraws_rect_add(e->engine.data.output, | ||
1431 | 0, 0, | ||
1432 | e->output.w, e->output.h); | ||
1433 | } | ||
1434 | /* phase 5. add obscures */ | ||
1435 | EINA_LIST_FOREACH(e->obscures, ll, r) | ||
1436 | { | ||
1437 | e->engine.func->output_redraws_rect_del(e->engine.data.output, | ||
1438 | r->x, r->y, r->w, r->h); | ||
1439 | } | ||
1440 | /* build obscure objects list of active objects that obscure */ | ||
1441 | for (i = 0; i < e->active_objects.count; ++i) | ||
1442 | { | ||
1443 | obj = eina_array_data_get(&e->active_objects, i); | ||
1444 | if (UNLIKELY((evas_object_is_opaque(obj) || | ||
1445 | ((obj->func->has_opaque_rect) && | ||
1446 | (obj->func->has_opaque_rect(obj)))) && | ||
1447 | evas_object_is_visible(obj) && | ||
1448 | (!obj->clip.clipees) && | ||
1449 | (obj->cur.visible) && | ||
1450 | (!obj->delete_me) && | ||
1451 | (obj->cur.cache.clip.visible) && | ||
1452 | (!obj->smart.smart))) | ||
1453 | /* obscuring_objects = eina_list_append(obscuring_objects, obj); */ | ||
1454 | eina_array_push(&e->obscuring_objects, obj); | ||
1455 | } | ||
1456 | |||
1457 | /* save this list */ | ||
1458 | /* obscuring_objects_orig = obscuring_objects; */ | ||
1459 | /* obscuring_objects = NULL; */ | ||
1460 | /* phase 6. go thru each update rect and render objects in it*/ | ||
1461 | if (do_draw) | ||
1462 | { | ||
1463 | unsigned int offset = 0; | ||
1464 | |||
1465 | while ((surface = | ||
1466 | e->engine.func->output_redraws_next_update_get | ||
1467 | (e->engine.data.output, | ||
1468 | &ux, &uy, &uw, &uh, | ||
1469 | &cx, &cy, &cw, &ch))) | ||
1470 | { | ||
1471 | int off_x, off_y; | ||
1472 | |||
1473 | RD(" [--- UPDATE %i %i %ix%i\n", ux, uy, uw, uh); | ||
1474 | if (make_updates) | ||
1475 | { | ||
1476 | Eina_Rectangle *rect; | ||
1477 | |||
1478 | NEW_RECT(rect, ux, uy, uw, uh); | ||
1479 | if (rect) | ||
1480 | updates = eina_list_append(updates, rect); | ||
1481 | } | ||
1482 | haveup = 1; | ||
1483 | off_x = cx - ux; | ||
1484 | off_y = cy - uy; | ||
1485 | /* build obscuring objects list (in order from bottom to top) */ | ||
1486 | for (i = 0; i < e->obscuring_objects.count; ++i) | ||
1487 | { | ||
1488 | obj = (Evas_Object *)eina_array_data_get | ||
1489 | (&e->obscuring_objects, i); | ||
1490 | if (evas_object_is_in_output_rect(obj, ux, uy, uw, uh)) | ||
1491 | { | ||
1492 | eina_array_push(&e->temporary_objects, obj); | ||
1493 | |||
1494 | /* reset the background of the area if needed (using cutout and engine alpha flag to help) */ | ||
1495 | if (alpha) | ||
1496 | _evas_render_cutout_add(e, obj, off_x, off_y); | ||
1497 | } | ||
1498 | } | ||
1499 | if (alpha) | ||
1500 | { | ||
1501 | e->engine.func->context_clip_set(e->engine.data.output, | ||
1502 | e->engine.data.context, | ||
1503 | ux + off_x, uy + off_y, uw, uh); | ||
1504 | e->engine.func->context_color_set(e->engine.data.output, | ||
1505 | e->engine.data.context, | ||
1506 | 0, 0, 0, 0); | ||
1507 | e->engine.func->context_multiplier_unset | ||
1508 | (e->engine.data.output, e->engine.data.context); | ||
1509 | e->engine.func->context_render_op_set(e->engine.data.output, | ||
1510 | e->engine.data.context, | ||
1511 | EVAS_RENDER_COPY); | ||
1512 | e->engine.func->rectangle_draw(e->engine.data.output, | ||
1513 | e->engine.data.context, | ||
1514 | surface, | ||
1515 | cx, cy, cw, ch); | ||
1516 | e->engine.func->context_cutout_clear(e->engine.data.output, | ||
1517 | e->engine.data.context); | ||
1518 | e->engine.func->context_clip_unset(e->engine.data.output, | ||
1519 | e->engine.data.context); | ||
1520 | } | ||
1521 | /* render all object that intersect with rect */ | ||
1522 | for (i = 0; i < e->active_objects.count; ++i) | ||
1523 | { | ||
1524 | obj = eina_array_data_get(&e->active_objects, i); | ||
1525 | |||
1526 | /* if it's in our outpout rect and it doesn't clip anything */ | ||
1527 | RD(" OBJ: [%p] '%s' %i %i %ix%i\n", obj, obj->type, obj->cur.geometry.x, obj->cur.geometry.y, obj->cur.geometry.w, obj->cur.geometry.h); | ||
1528 | if ((evas_object_is_in_output_rect(obj, ux, uy, uw, uh) || | ||
1529 | (obj->smart.smart)) && | ||
1530 | (!obj->clip.clipees) && | ||
1531 | (obj->cur.visible) && | ||
1532 | (!obj->delete_me) && | ||
1533 | (obj->cur.cache.clip.visible) && | ||
1534 | // (!obj->smart.smart) && | ||
1535 | ((obj->cur.color.a > 0 || obj->cur.render_op != EVAS_RENDER_BLEND))) | ||
1536 | { | ||
1537 | int x, y, w, h; | ||
1538 | |||
1539 | RD(" DRAW (vis: %i, a: %i, clipees: %p\n", obj->cur.visible, obj->cur.color.a, obj->clip.clipees); | ||
1540 | if ((e->temporary_objects.count > offset) && | ||
1541 | (eina_array_data_get(&e->temporary_objects, offset) == obj)) | ||
1542 | offset++; | ||
1543 | x = cx; y = cy; w = cw; h = ch; | ||
1544 | if (((w > 0) && (h > 0)) || (obj->smart.smart)) | ||
1545 | { | ||
1546 | if (!obj->smart.smart) | ||
1547 | { | ||
1548 | RECTS_CLIP_TO_RECT(x, y, w, h, | ||
1549 | obj->cur.cache.clip.x + off_x, | ||
1550 | obj->cur.cache.clip.y + off_y, | ||
1551 | obj->cur.cache.clip.w, | ||
1552 | obj->cur.cache.clip.h); | ||
1553 | } | ||
1554 | if (obj->cur.mask) | ||
1555 | e->engine.func->context_mask_set(e->engine.data.output, | ||
1556 | e->engine.data.context, | ||
1557 | obj->cur.mask->func->engine_data_get(obj->cur.mask), | ||
1558 | obj->cur.mask->cur.geometry.x + off_x, | ||
1559 | obj->cur.mask->cur.geometry.y + off_y, | ||
1560 | obj->cur.mask->cur.geometry.w, | ||
1561 | obj->cur.mask->cur.geometry.h); | ||
1562 | else | ||
1563 | e->engine.func->context_mask_unset(e->engine.data.output, | ||
1564 | e->engine.data.context); | ||
1565 | if (obj->cur.clipper) | ||
1566 | e->engine.func->context_clip_set(e->engine.data.output, | ||
1567 | e->engine.data.context, | ||
1568 | x, y, w, h); | ||
1569 | else | ||
1570 | e->engine.func->context_clip_unset(e->engine.data.output, | ||
1571 | e->engine.data.context); | ||
1572 | #if 1 /* FIXME: this can slow things down... figure out optimum... coverage */ | ||
1573 | for (j = offset; j < e->temporary_objects.count; ++j) | ||
1574 | { | ||
1575 | Evas_Object *obj2; | ||
1576 | |||
1577 | obj2 = (Evas_Object *)eina_array_data_get | ||
1578 | (&e->temporary_objects, j); | ||
1579 | _evas_render_cutout_add(e, obj2, off_x, off_y); | ||
1580 | } | ||
1581 | #endif | ||
1582 | e->engine.func->context_clip_set(e->engine.data.output, | ||
1583 | e->engine.data.context, | ||
1584 | x, y, w, h); | ||
1585 | clean_them |= evas_render_mapped(e, obj, e->engine.data.context, | ||
1586 | surface, off_x, off_y, 0, | ||
1587 | cx, cy, cw, ch | ||
1588 | #ifdef REND_DGB | ||
1589 | , 1 | ||
1590 | #endif | ||
1591 | ); | ||
1592 | e->engine.func->context_cutout_clear(e->engine.data.output, | ||
1593 | e->engine.data.context); | ||
1594 | } | ||
1595 | } | ||
1596 | } | ||
1597 | /* punch rect out */ | ||
1598 | e->engine.func->output_redraws_next_update_push(e->engine.data.output, | ||
1599 | surface, | ||
1600 | ux, uy, uw, uh); | ||
1601 | /* free obscuring objects list */ | ||
1602 | eina_array_clean(&e->temporary_objects); | ||
1603 | RD(" ---]\n"); | ||
1604 | } | ||
1605 | /* flush redraws */ | ||
1606 | if (haveup) | ||
1607 | { | ||
1608 | evas_event_callback_call(e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL); | ||
1609 | e->engine.func->output_flush(e->engine.data.output); | ||
1610 | evas_event_callback_call(e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL); | ||
1611 | } | ||
1612 | } | ||
1613 | /* clear redraws */ | ||
1614 | e->engine.func->output_redraws_clear(e->engine.data.output); | ||
1615 | /* and do a post render pass */ | ||
1616 | for (i = 0; i < e->active_objects.count; ++i) | ||
1617 | { | ||
1618 | obj = eina_array_data_get(&e->active_objects, i); | ||
1619 | obj->pre_render_done = 0; | ||
1620 | RD(" OBJ [%p] post... %i %i\n", obj, obj->changed, do_draw); | ||
1621 | if ((obj->changed) && (do_draw)) | ||
1622 | { | ||
1623 | RD(" OBJ [%p] post... func1\n", obj); | ||
1624 | obj->func->render_post(obj); | ||
1625 | obj->restack = 0; | ||
1626 | obj->changed = 0; | ||
1627 | obj->changed_move_only = 0; | ||
1628 | obj->changed_nomove = 0; | ||
1629 | obj->changed_move = 0; | ||
1630 | } | ||
1631 | else if ((obj->cur.map != obj->prev.map) || | ||
1632 | (obj->cur.usemap != obj->prev.usemap)) | ||
1633 | { | ||
1634 | RD(" OBJ [%p] post... func2\n", obj); | ||
1635 | obj->func->render_post(obj); | ||
1636 | obj->restack = 0; | ||
1637 | obj->changed = 0; | ||
1638 | obj->changed_move_only = 0; | ||
1639 | obj->changed_nomove = 0; | ||
1640 | obj->changed_move = 0; | ||
1641 | } | ||
1642 | /* moved to other pre-process phase 1 | ||
1643 | if (obj->delete_me == 2) | ||
1644 | { | ||
1645 | delete_objects = eina_list_append(delete_objects, obj); | ||
1646 | } | ||
1647 | else if (obj->delete_me != 0) obj->delete_me++; | ||
1648 | */ | ||
1649 | } | ||
1650 | /* free our obscuring object list */ | ||
1651 | eina_array_clean(&e->obscuring_objects); | ||
1652 | |||
1653 | /* If some object are still marked as changed, do not remove | ||
1654 | them from the pending list. */ | ||
1655 | eina_array_remove(&e->pending_objects, pending_change, NULL); | ||
1656 | |||
1657 | for (i = 0; i < e->render_objects.count; ++i) | ||
1658 | { | ||
1659 | obj = eina_array_data_get(&e->render_objects, i); | ||
1660 | obj->pre_render_done = 0; | ||
1661 | } | ||
1662 | |||
1663 | /* delete all objects flagged for deletion now */ | ||
1664 | for (i = 0; i < e->delete_objects.count; ++i) | ||
1665 | { | ||
1666 | obj = eina_array_data_get(&e->delete_objects, i); | ||
1667 | evas_object_free(obj, 1); | ||
1668 | } | ||
1669 | eina_array_clean(&e->delete_objects); | ||
1670 | |||
1671 | e->changed = 0; | ||
1672 | e->viewport.changed = 0; | ||
1673 | e->output.changed = 0; | ||
1674 | e->invalidate = 0; | ||
1675 | |||
1676 | /* If their are some object to restack or some object to delete, | ||
1677 | * it's useless to keep the render object list around. */ | ||
1678 | if (clean_them) | ||
1679 | { | ||
1680 | eina_array_clean(&e->active_objects); | ||
1681 | eina_array_clean(&e->render_objects); | ||
1682 | eina_array_clean(&e->restack_objects); | ||
1683 | eina_array_clean(&e->delete_objects); | ||
1684 | eina_array_clean(&e->obscuring_objects); | ||
1685 | e->invalidate = 1; | ||
1686 | } | ||
1687 | |||
1688 | evas_module_clean(); | ||
1689 | |||
1690 | RD("---]\n"); | ||
1691 | |||
1692 | return updates; | ||
1693 | } | ||
1694 | |||
1695 | EAPI void | ||
1696 | evas_render_updates_free(Eina_List *updates) | ||
1697 | { | ||
1698 | Eina_Rectangle *r; | ||
1699 | |||
1700 | EINA_LIST_FREE(updates, r) | ||
1701 | eina_rectangle_free(r); | ||
1702 | } | ||
1703 | |||
1704 | EAPI Eina_List * | ||
1705 | evas_render_updates(Evas *e) | ||
1706 | { | ||
1707 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1708 | return NULL; | ||
1709 | MAGIC_CHECK_END(); | ||
1710 | |||
1711 | #ifdef EVAS_FRAME_QUEUING | ||
1712 | evas_common_frameq_flush_ready (); | ||
1713 | #endif | ||
1714 | |||
1715 | if (!e->changed) return NULL; | ||
1716 | return evas_render_updates_internal(e, 1, 1); | ||
1717 | } | ||
1718 | |||
1719 | EAPI void | ||
1720 | evas_render(Evas *e) | ||
1721 | { | ||
1722 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1723 | return; | ||
1724 | MAGIC_CHECK_END(); | ||
1725 | |||
1726 | #ifdef EVAS_FRAME_QUEUING | ||
1727 | evas_common_frameq_flush_ready (); | ||
1728 | #endif | ||
1729 | |||
1730 | if (!e->changed) return; | ||
1731 | evas_render_updates_internal(e, 0, 1); | ||
1732 | } | ||
1733 | |||
1734 | EAPI void | ||
1735 | evas_norender(Evas *e) | ||
1736 | { | ||
1737 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1738 | return; | ||
1739 | MAGIC_CHECK_END(); | ||
1740 | |||
1741 | // if (!e->changed) return; | ||
1742 | evas_render_updates_internal(e, 0, 0); | ||
1743 | } | ||
1744 | |||
1745 | EAPI void | ||
1746 | evas_render_idle_flush(Evas *e) | ||
1747 | { | ||
1748 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1749 | return; | ||
1750 | MAGIC_CHECK_END(); | ||
1751 | |||
1752 | evas_fonts_zero_presure(e); | ||
1753 | |||
1754 | if ((e->engine.func) && (e->engine.func->output_idle_flush) && | ||
1755 | (e->engine.data.output)) | ||
1756 | e->engine.func->output_idle_flush(e->engine.data.output); | ||
1757 | |||
1758 | eina_array_flush(&e->delete_objects); | ||
1759 | eina_array_flush(&e->active_objects); | ||
1760 | eina_array_flush(&e->restack_objects); | ||
1761 | eina_array_flush(&e->render_objects); | ||
1762 | eina_array_flush(&e->clip_changes); | ||
1763 | |||
1764 | e->invalidate = 1; | ||
1765 | } | ||
1766 | |||
1767 | EAPI void | ||
1768 | evas_sync(Evas *e) | ||
1769 | { | ||
1770 | #ifdef EVAS_FRAME_QUEUING | ||
1771 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1772 | return; | ||
1773 | MAGIC_CHECK_END(); | ||
1774 | |||
1775 | evas_common_frameq_flush(); | ||
1776 | #else | ||
1777 | (void) e; | ||
1778 | #endif | ||
1779 | } | ||
1780 | |||
1781 | static void | ||
1782 | _evas_render_dump_map_surfaces(Evas_Object *obj) | ||
1783 | { | ||
1784 | if ((obj->cur.map) && obj->cur.map->surface) | ||
1785 | { | ||
1786 | obj->layer->evas->engine.func->image_map_surface_free | ||
1787 | (obj->layer->evas->engine.data.output, obj->cur.map->surface); | ||
1788 | obj->cur.map->surface = NULL; | ||
1789 | } | ||
1790 | |||
1791 | if (obj->smart.smart) | ||
1792 | { | ||
1793 | Evas_Object *obj2; | ||
1794 | |||
1795 | EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(obj), obj2) | ||
1796 | _evas_render_dump_map_surfaces(obj2); | ||
1797 | } | ||
1798 | } | ||
1799 | |||
1800 | EAPI void | ||
1801 | evas_render_dump(Evas *e) | ||
1802 | { | ||
1803 | Evas_Layer *lay; | ||
1804 | |||
1805 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1806 | return; | ||
1807 | MAGIC_CHECK_END(); | ||
1808 | |||
1809 | EINA_INLIST_FOREACH(e->layers, lay) | ||
1810 | { | ||
1811 | Evas_Object *obj; | ||
1812 | |||
1813 | EINA_INLIST_FOREACH(lay->objects, obj) | ||
1814 | { | ||
1815 | if ((obj->type) && (!strcmp(obj->type, "image"))) | ||
1816 | evas_object_inform_call_image_unloaded(obj); | ||
1817 | _evas_render_dump_map_surfaces(obj); | ||
1818 | } | ||
1819 | } | ||
1820 | if ((e->engine.func) && (e->engine.func->output_dump) && | ||
1821 | (e->engine.data.output)) | ||
1822 | e->engine.func->output_dump(e->engine.data.output); | ||
1823 | } | ||
1824 | |||
1825 | void | ||
1826 | evas_render_invalidate(Evas *e) | ||
1827 | { | ||
1828 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
1829 | return; | ||
1830 | MAGIC_CHECK_END(); | ||
1831 | |||
1832 | eina_array_clean(&e->active_objects); | ||
1833 | eina_array_clean(&e->render_objects); | ||
1834 | |||
1835 | eina_array_flush(&e->restack_objects); | ||
1836 | eina_array_flush(&e->delete_objects); | ||
1837 | |||
1838 | e->invalidate = 1; | ||
1839 | } | ||
1840 | |||
1841 | void | ||
1842 | evas_render_object_recalc(Evas_Object *obj) | ||
1843 | { | ||
1844 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
1845 | return; | ||
1846 | MAGIC_CHECK_END(); | ||
1847 | |||
1848 | #ifndef EVAS_FRAME_QUEUING | ||
1849 | if ((!obj->changed) && (obj->delete_me < 2)) | ||
1850 | #else | ||
1851 | if ((!obj->changed)) | ||
1852 | #endif | ||
1853 | { | ||
1854 | Evas *e; | ||
1855 | |||
1856 | e = obj->layer->evas; | ||
1857 | if ((!e) || (e->cleanup)) return; | ||
1858 | #ifdef EVAS_FRAME_QUEUING | ||
1859 | if (obj->delete_me >= evas_common_frameq_get_frameq_sz() + 2) return; | ||
1860 | #endif | ||
1861 | eina_array_push(&e->pending_objects, obj); | ||
1862 | obj->changed = 1; | ||
1863 | } | ||
1864 | } | ||
1865 | |||
1866 | /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/ | ||
diff --git a/libraries/evas/src/lib/canvas/evas_smart.c b/libraries/evas/src/lib/canvas/evas_smart.c new file mode 100644 index 0000000..0cfba05 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_smart.c | |||
@@ -0,0 +1,266 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | |||
5 | static void _evas_smart_class_callbacks_create(Evas_Smart *s); | ||
6 | |||
7 | /* all public */ | ||
8 | |||
9 | EAPI void | ||
10 | evas_smart_free(Evas_Smart *s) | ||
11 | { | ||
12 | MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); | ||
13 | return; | ||
14 | MAGIC_CHECK_END(); | ||
15 | s->delete_me = 1; | ||
16 | if (s->usage > 0) return; | ||
17 | if (s->class_allocated) free((void *)s->smart_class); | ||
18 | free(s->callbacks.array); | ||
19 | free(s); | ||
20 | } | ||
21 | |||
22 | EAPI Evas_Smart * | ||
23 | evas_smart_class_new(const Evas_Smart_Class *sc) | ||
24 | { | ||
25 | Evas_Smart *s; | ||
26 | |||
27 | if (!sc) return NULL; | ||
28 | |||
29 | /* api does not match abi! for now refuse as we only have 1 version */ | ||
30 | if (sc->version != EVAS_SMART_CLASS_VERSION) return NULL; | ||
31 | |||
32 | s = evas_mem_calloc(sizeof(Evas_Smart)); | ||
33 | if (!s) return NULL; | ||
34 | |||
35 | s->magic = MAGIC_SMART; | ||
36 | |||
37 | s->smart_class = sc; | ||
38 | _evas_smart_class_callbacks_create(s); | ||
39 | |||
40 | return s; | ||
41 | } | ||
42 | |||
43 | EAPI const Evas_Smart_Class * | ||
44 | evas_smart_class_get(const Evas_Smart *s) | ||
45 | { | ||
46 | MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); | ||
47 | return NULL; | ||
48 | MAGIC_CHECK_END(); | ||
49 | return s->smart_class; | ||
50 | } | ||
51 | |||
52 | EAPI void * | ||
53 | evas_smart_data_get(const Evas_Smart *s) | ||
54 | { | ||
55 | MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); | ||
56 | return NULL; | ||
57 | MAGIC_CHECK_END(); | ||
58 | return (void *)s->smart_class->data; | ||
59 | } | ||
60 | |||
61 | EAPI const Evas_Smart_Cb_Description ** | ||
62 | evas_smart_callbacks_descriptions_get(const Evas_Smart *s, unsigned int *count) | ||
63 | { | ||
64 | MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); | ||
65 | if (count) *count = 0; | ||
66 | return NULL; | ||
67 | MAGIC_CHECK_END(); | ||
68 | |||
69 | if (count) *count = s->callbacks.size; | ||
70 | return s->callbacks.array; | ||
71 | } | ||
72 | |||
73 | EAPI const Evas_Smart_Cb_Description * | ||
74 | evas_smart_callback_description_find(const Evas_Smart *s, const char *name) | ||
75 | { | ||
76 | if (!name) return NULL; | ||
77 | MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); | ||
78 | return NULL; | ||
79 | MAGIC_CHECK_END(); | ||
80 | return evas_smart_cb_description_find(&s->callbacks, name); | ||
81 | } | ||
82 | |||
83 | EAPI Eina_Bool | ||
84 | evas_smart_class_inherit_full(Evas_Smart_Class *sc, const Evas_Smart_Class *parent_sc, unsigned int parent_sc_size) | ||
85 | { | ||
86 | unsigned int off; | ||
87 | |||
88 | /* api does not match abi! for now refuse as we only have 1 version */ | ||
89 | if (parent_sc->version != EVAS_SMART_CLASS_VERSION) return EINA_FALSE; | ||
90 | |||
91 | #define _CP(m) sc->m = parent_sc->m | ||
92 | _CP(add); | ||
93 | _CP(del); | ||
94 | _CP(move); | ||
95 | _CP(resize); | ||
96 | _CP(show); | ||
97 | _CP(hide); | ||
98 | _CP(color_set); | ||
99 | _CP(clip_set); | ||
100 | _CP(clip_unset); | ||
101 | _CP(calculate); | ||
102 | _CP(member_add); | ||
103 | _CP(member_del); | ||
104 | #undef _CP | ||
105 | |||
106 | sc->parent = parent_sc; | ||
107 | |||
108 | off = sizeof(Evas_Smart_Class); | ||
109 | if (parent_sc_size == off) return EINA_TRUE; | ||
110 | |||
111 | memcpy(((char *)sc) + off, ((char *)parent_sc) + off, parent_sc_size - off); | ||
112 | return EINA_TRUE; | ||
113 | } | ||
114 | |||
115 | EAPI int | ||
116 | evas_smart_usage_get(const Evas_Smart *s) | ||
117 | { | ||
118 | MAGIC_CHECK(s, Evas_Smart, MAGIC_SMART); | ||
119 | return 0; | ||
120 | MAGIC_CHECK_END(); | ||
121 | return s->usage; | ||
122 | } | ||
123 | |||
124 | |||
125 | /* internal funcs */ | ||
126 | void | ||
127 | evas_object_smart_use(Evas_Smart *s) | ||
128 | { | ||
129 | s->usage++; | ||
130 | } | ||
131 | |||
132 | void | ||
133 | evas_object_smart_unuse(Evas_Smart *s) | ||
134 | { | ||
135 | s->usage--; | ||
136 | if ((s->usage <= 0) && (s->delete_me)) evas_smart_free(s); | ||
137 | } | ||
138 | |||
139 | Eina_Bool | ||
140 | evas_smart_cb_descriptions_resize(Evas_Smart_Cb_Description_Array *a, unsigned int size) | ||
141 | { | ||
142 | void *tmp; | ||
143 | |||
144 | if (size == a->size) | ||
145 | return EINA_TRUE; | ||
146 | |||
147 | if (size == EINA_FALSE) | ||
148 | { | ||
149 | free(a->array); | ||
150 | a->array = NULL; | ||
151 | a->size = 0; | ||
152 | return EINA_TRUE; | ||
153 | } | ||
154 | |||
155 | tmp = realloc(a->array, (size + 1) * sizeof(Evas_Smart_Cb_Description *)); | ||
156 | if (tmp) | ||
157 | { | ||
158 | a->array = tmp; | ||
159 | a->size = size; | ||
160 | a->array[size] = NULL; | ||
161 | return EINA_TRUE; | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | ERR("realloc failed!"); | ||
166 | return EINA_FALSE; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static int | ||
171 | _evas_smart_cb_description_cmp_sort(const void *p1, const void *p2) | ||
172 | { | ||
173 | const Evas_Smart_Cb_Description **a = (const Evas_Smart_Cb_Description **)p1; | ||
174 | const Evas_Smart_Cb_Description **b = (const Evas_Smart_Cb_Description **)p2; | ||
175 | return strcmp((*a)->name, (*b)->name); | ||
176 | } | ||
177 | |||
178 | void | ||
179 | evas_smart_cb_descriptions_fix(Evas_Smart_Cb_Description_Array *a) | ||
180 | { | ||
181 | unsigned int i, j; | ||
182 | |||
183 | if (!a) | ||
184 | { | ||
185 | ERR("no array to fix!"); | ||
186 | return; | ||
187 | } | ||
188 | |||
189 | qsort(a->array, a->size, sizeof(Evas_Smart_Cb_Description *), | ||
190 | _evas_smart_cb_description_cmp_sort); | ||
191 | |||
192 | DBG("%u callbacks", a->size); | ||
193 | if (a->size) | ||
194 | DBG("%s [type=%s]", a->array[0]->name, a->array[0]->type); | ||
195 | |||
196 | for (i = 0, j = 1; j < a->size; j++) | ||
197 | { | ||
198 | const Evas_Smart_Cb_Description *cur, *prev; | ||
199 | |||
200 | cur = a->array[j]; | ||
201 | prev = a->array[i]; | ||
202 | |||
203 | DBG("%s [type=%s]", cur->name, cur->type); | ||
204 | |||
205 | if (strcmp(cur->name, prev->name) != 0) | ||
206 | { | ||
207 | i++; | ||
208 | if (i != j) | ||
209 | a->array[i] = a->array[j]; | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | if (strcmp(cur->type, prev->type) == 0) | ||
214 | WRN("duplicated smart callback description" | ||
215 | " with name '%s' and type '%s'", cur->name, cur->type); | ||
216 | else | ||
217 | ERR("callback descriptions named '%s' differ" | ||
218 | " in type, keeping '%s', ignoring '%s'", | ||
219 | cur->name, prev->type, cur->type); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | evas_smart_cb_descriptions_resize(a, i + 1); | ||
224 | } | ||
225 | |||
226 | static void | ||
227 | _evas_smart_class_callbacks_create(Evas_Smart *s) | ||
228 | { | ||
229 | const Evas_Smart_Class *sc; | ||
230 | unsigned int n = 0; | ||
231 | |||
232 | for (sc = s->smart_class; sc; sc = sc->parent) | ||
233 | { | ||
234 | const Evas_Smart_Cb_Description *d; | ||
235 | for (d = sc->callbacks; d && d->name; d++) | ||
236 | n++; | ||
237 | } | ||
238 | |||
239 | if (n == 0) return; | ||
240 | if (!evas_smart_cb_descriptions_resize(&s->callbacks, n)) return; | ||
241 | for (n = 0, sc = s->smart_class; sc; sc = sc->parent) | ||
242 | { | ||
243 | const Evas_Smart_Cb_Description *d; | ||
244 | for (d = sc->callbacks; d && d->name; d++) | ||
245 | s->callbacks.array[n++] = d; | ||
246 | } | ||
247 | evas_smart_cb_descriptions_fix(&s->callbacks); | ||
248 | } | ||
249 | |||
250 | static int | ||
251 | _evas_smart_cb_description_cmp_search(const void *p1, const void *p2) | ||
252 | { | ||
253 | const char *name = p1; | ||
254 | const Evas_Smart_Cb_Description **v = (const Evas_Smart_Cb_Description **)p2; | ||
255 | /* speed up string shares searches (same pointers) */ | ||
256 | if (name == (*v)->name) return 0; | ||
257 | return strcmp(name, (*v)->name); | ||
258 | } | ||
259 | |||
260 | const Evas_Smart_Cb_Description * | ||
261 | evas_smart_cb_description_find(const Evas_Smart_Cb_Description_Array *a, const char *name) | ||
262 | { | ||
263 | if (!a->array) return NULL; | ||
264 | return bsearch(name, a->array, a->size, sizeof(Evas_Smart_Cb_Description *), | ||
265 | _evas_smart_cb_description_cmp_search); | ||
266 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_stack.c b/libraries/evas/src/lib/canvas/evas_stack.c new file mode 100644 index 0000000..a8dec0d --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_stack.c | |||
@@ -0,0 +1,391 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | static Evas_Object * | ||
5 | evas_object_above_get_internal(const Evas_Object *obj) | ||
6 | { | ||
7 | if ((EINA_INLIST_GET(obj))->next) | ||
8 | return (Evas_Object *)((EINA_INLIST_GET(obj))->next); | ||
9 | else | ||
10 | { | ||
11 | if ((EINA_INLIST_GET(((Evas_Object*)(obj))->layer))->next) | ||
12 | { | ||
13 | Evas_Layer *l; | ||
14 | |||
15 | l = (Evas_Layer *)((EINA_INLIST_GET((((Evas_Object *)obj)->layer)))->next); | ||
16 | return l->objects; | ||
17 | } | ||
18 | } | ||
19 | return NULL; | ||
20 | } | ||
21 | |||
22 | static Evas_Object * | ||
23 | evas_object_below_get_internal(const Evas_Object *obj) | ||
24 | { | ||
25 | if ((EINA_INLIST_GET(obj))->prev) | ||
26 | return (Evas_Object *)((EINA_INLIST_GET(obj))->prev); | ||
27 | else | ||
28 | { | ||
29 | if ((EINA_INLIST_GET((((Evas_Object *)obj)->layer)))->prev) | ||
30 | { | ||
31 | Evas_Layer *l; | ||
32 | |||
33 | l = (Evas_Layer *)((EINA_INLIST_GET((((Evas_Object *)obj)->layer)))->prev); | ||
34 | return (Evas_Object *)((EINA_INLIST_GET((l->objects)))->last); | ||
35 | } | ||
36 | } | ||
37 | return NULL; | ||
38 | } | ||
39 | |||
40 | EAPI void | ||
41 | evas_object_raise(Evas_Object *obj) | ||
42 | { | ||
43 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
44 | return; | ||
45 | MAGIC_CHECK_END(); | ||
46 | if (evas_object_intercept_call_raise(obj)) return; | ||
47 | if (!((EINA_INLIST_GET(obj))->next)) | ||
48 | { | ||
49 | evas_object_inform_call_restack(obj); | ||
50 | return; | ||
51 | } | ||
52 | if (obj->smart.parent) | ||
53 | evas_object_smart_member_raise(obj); | ||
54 | else | ||
55 | { | ||
56 | if (obj->in_layer) | ||
57 | obj->layer->objects = (Evas_Object *)eina_inlist_demote(EINA_INLIST_GET(obj->layer->objects), EINA_INLIST_GET(obj)); | ||
58 | } | ||
59 | if (obj->clip.clipees) | ||
60 | { | ||
61 | evas_object_inform_call_restack(obj); | ||
62 | return; | ||
63 | } | ||
64 | if (obj->layer) evas_render_invalidate(obj->layer->evas); | ||
65 | obj->restack = EINA_TRUE; | ||
66 | evas_object_change(obj); | ||
67 | evas_object_inform_call_restack(obj); | ||
68 | if (obj->layer->evas->events_frozen > 0) return; | ||
69 | if ((!evas_event_passes_through(obj)) && (!evas_event_freezes_through(obj))) | ||
70 | { | ||
71 | if (!obj->smart.smart) | ||
72 | { | ||
73 | if (evas_object_is_in_output_rect(obj, | ||
74 | obj->layer->evas->pointer.x, | ||
75 | obj->layer->evas->pointer.y, | ||
76 | 1, 1) && obj->cur.visible) | ||
77 | evas_event_feed_mouse_move(obj->layer->evas, | ||
78 | obj->layer->evas->pointer.x, | ||
79 | obj->layer->evas->pointer.y, | ||
80 | obj->layer->evas->last_timestamp, | ||
81 | NULL); | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | EAPI void | ||
87 | evas_object_lower(Evas_Object *obj) | ||
88 | { | ||
89 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
90 | return; | ||
91 | MAGIC_CHECK_END(); | ||
92 | if (evas_object_intercept_call_lower(obj)) return; | ||
93 | if (!((EINA_INLIST_GET(obj))->prev)) | ||
94 | { | ||
95 | evas_object_inform_call_restack(obj); | ||
96 | return; | ||
97 | } | ||
98 | if (obj->smart.parent) | ||
99 | evas_object_smart_member_lower(obj); | ||
100 | else | ||
101 | { | ||
102 | if (obj->in_layer) | ||
103 | obj->layer->objects = (Evas_Object *)eina_inlist_promote(EINA_INLIST_GET(obj->layer->objects), | ||
104 | EINA_INLIST_GET(obj)); | ||
105 | } | ||
106 | if (obj->clip.clipees) | ||
107 | { | ||
108 | evas_object_inform_call_restack(obj); | ||
109 | return; | ||
110 | } | ||
111 | if (obj->layer) evas_render_invalidate(obj->layer->evas); | ||
112 | obj->restack = EINA_TRUE; | ||
113 | evas_object_change(obj); | ||
114 | evas_object_inform_call_restack(obj); | ||
115 | if (obj->layer->evas->events_frozen > 0) return; | ||
116 | if ((!evas_event_passes_through(obj)) && (!evas_event_freezes_through(obj))) | ||
117 | { | ||
118 | if (!obj->smart.smart) | ||
119 | { | ||
120 | if (evas_object_is_in_output_rect(obj, | ||
121 | obj->layer->evas->pointer.x, | ||
122 | obj->layer->evas->pointer.y, | ||
123 | 1, 1) && obj->cur.visible) | ||
124 | evas_event_feed_mouse_move(obj->layer->evas, | ||
125 | obj->layer->evas->pointer.x, | ||
126 | obj->layer->evas->pointer.y, | ||
127 | obj->layer->evas->last_timestamp, | ||
128 | NULL); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | EAPI void | ||
134 | evas_object_stack_above(Evas_Object *obj, Evas_Object *above) | ||
135 | { | ||
136 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
137 | return; | ||
138 | MAGIC_CHECK_END(); | ||
139 | MAGIC_CHECK(above, Evas_Object, MAGIC_OBJ); | ||
140 | return; | ||
141 | MAGIC_CHECK_END(); | ||
142 | if (obj == above) return; | ||
143 | if (evas_object_intercept_call_stack_above(obj, above)) return; | ||
144 | if (!above) | ||
145 | { | ||
146 | evas_object_raise(obj); | ||
147 | return; | ||
148 | } | ||
149 | if ((EINA_INLIST_GET(obj))->prev == EINA_INLIST_GET(above)) | ||
150 | { | ||
151 | evas_object_inform_call_restack(obj); | ||
152 | return; | ||
153 | } | ||
154 | if (obj->smart.parent) | ||
155 | { | ||
156 | if (obj->smart.parent != above->smart.parent) | ||
157 | { | ||
158 | ERR("BITCH! evas_object_stack_above(), %p not inside same smart as %p!", obj, above); | ||
159 | return; | ||
160 | } | ||
161 | evas_object_smart_member_stack_above(obj, above); | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | if (above->smart.parent) | ||
166 | { | ||
167 | ERR("BITCH! evas_object_stack_above(), %p stack above %p, but above has smart parent, obj does not", obj, above); | ||
168 | return; | ||
169 | } | ||
170 | if (obj->layer != above->layer) | ||
171 | { | ||
172 | ERR("BITCH! evas_object_stack_above(), %p stack above %p, not matching layers", obj, above); | ||
173 | return; | ||
174 | } | ||
175 | if (obj->in_layer) | ||
176 | { | ||
177 | obj->layer->objects = (Evas_Object *)eina_inlist_remove(EINA_INLIST_GET(obj->layer->objects), | ||
178 | EINA_INLIST_GET(obj)); | ||
179 | obj->layer->objects = (Evas_Object *)eina_inlist_append_relative(EINA_INLIST_GET(obj->layer->objects), | ||
180 | EINA_INLIST_GET(obj), | ||
181 | EINA_INLIST_GET(above)); | ||
182 | } | ||
183 | } | ||
184 | if (obj->clip.clipees) | ||
185 | { | ||
186 | evas_object_inform_call_restack(obj); | ||
187 | return; | ||
188 | } | ||
189 | if (obj->layer) evas_render_invalidate(obj->layer->evas); | ||
190 | obj->restack = EINA_TRUE; | ||
191 | evas_object_change(obj); | ||
192 | evas_object_inform_call_restack(obj); | ||
193 | if (obj->layer->evas->events_frozen > 0) return; | ||
194 | if ((!evas_event_passes_through(obj)) && (!evas_event_freezes_through(obj))) | ||
195 | { | ||
196 | if (!obj->smart.smart) | ||
197 | { | ||
198 | if (evas_object_is_in_output_rect(obj, | ||
199 | obj->layer->evas->pointer.x, | ||
200 | obj->layer->evas->pointer.y, | ||
201 | 1, 1) && obj->cur.visible) | ||
202 | evas_event_feed_mouse_move(obj->layer->evas, | ||
203 | obj->layer->evas->pointer.x, | ||
204 | obj->layer->evas->pointer.y, | ||
205 | obj->layer->evas->last_timestamp, | ||
206 | NULL); | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | EAPI void | ||
212 | evas_object_stack_below(Evas_Object *obj, Evas_Object *below) | ||
213 | { | ||
214 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
215 | return; | ||
216 | MAGIC_CHECK_END(); | ||
217 | MAGIC_CHECK(below, Evas_Object, MAGIC_OBJ); | ||
218 | return; | ||
219 | MAGIC_CHECK_END(); | ||
220 | if (obj == below) return; | ||
221 | if (evas_object_intercept_call_stack_below(obj, below)) return; | ||
222 | if (!below) | ||
223 | { | ||
224 | evas_object_lower(obj); | ||
225 | return; | ||
226 | } | ||
227 | if ((EINA_INLIST_GET(obj))->next == EINA_INLIST_GET(below)) | ||
228 | { | ||
229 | evas_object_inform_call_restack(obj); | ||
230 | return; | ||
231 | } | ||
232 | if (obj->smart.parent) | ||
233 | { | ||
234 | if (obj->smart.parent != below->smart.parent) | ||
235 | { | ||
236 | ERR("BITCH! evas_object_stack_below(), %p not inside same smart as %p!", obj, below); | ||
237 | return; | ||
238 | } | ||
239 | evas_object_smart_member_stack_below(obj, below); | ||
240 | } | ||
241 | else | ||
242 | { | ||
243 | if (below->smart.parent) | ||
244 | { | ||
245 | ERR("BITCH! evas_object_stack_below(), %p stack below %p, but below has smart parent, obj does not", obj, below); | ||
246 | return; | ||
247 | } | ||
248 | if (obj->layer != below->layer) | ||
249 | { | ||
250 | ERR("BITCH! evas_object_stack_below(), %p stack below %p, not matching layers", obj, below); | ||
251 | return; | ||
252 | } | ||
253 | if (obj->in_layer) | ||
254 | { | ||
255 | obj->layer->objects = (Evas_Object *)eina_inlist_remove(EINA_INLIST_GET(obj->layer->objects), | ||
256 | EINA_INLIST_GET(obj)); | ||
257 | obj->layer->objects = (Evas_Object *)eina_inlist_prepend_relative(EINA_INLIST_GET(obj->layer->objects), | ||
258 | EINA_INLIST_GET(obj), | ||
259 | EINA_INLIST_GET(below)); | ||
260 | } | ||
261 | } | ||
262 | if (obj->clip.clipees) | ||
263 | { | ||
264 | evas_object_inform_call_restack(obj); | ||
265 | return; | ||
266 | } | ||
267 | if (obj->layer) evas_render_invalidate(obj->layer->evas); | ||
268 | obj->restack = EINA_TRUE; | ||
269 | evas_object_change(obj); | ||
270 | evas_object_inform_call_restack(obj); | ||
271 | if (obj->layer->evas->events_frozen > 0) return; | ||
272 | if ((!evas_event_passes_through(obj)) && (!evas_event_freezes_through(obj))) | ||
273 | { | ||
274 | if (!obj->smart.smart) | ||
275 | { | ||
276 | if (evas_object_is_in_output_rect(obj, | ||
277 | obj->layer->evas->pointer.x, | ||
278 | obj->layer->evas->pointer.y, | ||
279 | 1, 1) && obj->cur.visible) | ||
280 | evas_event_feed_mouse_move(obj->layer->evas, | ||
281 | obj->layer->evas->pointer.x, | ||
282 | obj->layer->evas->pointer.y, | ||
283 | obj->layer->evas->last_timestamp, | ||
284 | NULL); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | EAPI Evas_Object * | ||
290 | evas_object_above_get(const Evas_Object *obj) | ||
291 | { | ||
292 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
293 | return NULL; | ||
294 | MAGIC_CHECK_END(); | ||
295 | if (obj->smart.parent) | ||
296 | { | ||
297 | do | ||
298 | { | ||
299 | obj = (Evas_Object *)((EINA_INLIST_GET(obj))->next); | ||
300 | if ((obj) && (!obj->delete_me)) return (Evas_Object *)obj; | ||
301 | } | ||
302 | while (obj); | ||
303 | return NULL; | ||
304 | } | ||
305 | obj = evas_object_above_get_internal(obj); | ||
306 | while (obj) | ||
307 | { | ||
308 | if (!obj->delete_me) return (Evas_Object *)obj; | ||
309 | obj = evas_object_above_get_internal(obj); | ||
310 | } | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
314 | EAPI Evas_Object * | ||
315 | evas_object_below_get(const Evas_Object *obj) | ||
316 | { | ||
317 | MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ); | ||
318 | return NULL; | ||
319 | MAGIC_CHECK_END(); | ||
320 | if (obj->smart.parent) | ||
321 | { | ||
322 | do | ||
323 | { | ||
324 | obj = (Evas_Object *)((EINA_INLIST_GET(obj))->prev); | ||
325 | if ((obj) && (!obj->delete_me)) return (Evas_Object *)obj; | ||
326 | } | ||
327 | while (obj); | ||
328 | return NULL; | ||
329 | } | ||
330 | obj = evas_object_below_get_internal(obj); | ||
331 | while (obj) | ||
332 | { | ||
333 | if (!obj->delete_me) return (Evas_Object *)obj; | ||
334 | obj = evas_object_below_get_internal(obj); | ||
335 | } | ||
336 | return NULL; | ||
337 | } | ||
338 | |||
339 | |||
340 | |||
341 | EAPI Evas_Object * | ||
342 | evas_object_bottom_get(const Evas *e) | ||
343 | { | ||
344 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
345 | return NULL; | ||
346 | MAGIC_CHECK_END(); | ||
347 | if (e->layers) | ||
348 | { | ||
349 | Evas_Object *obj; | ||
350 | |||
351 | obj = e->layers->objects; | ||
352 | while (obj) | ||
353 | { | ||
354 | if (!obj->delete_me) return obj; | ||
355 | obj = evas_object_above_get_internal(obj); | ||
356 | } | ||
357 | } | ||
358 | return NULL; | ||
359 | } | ||
360 | |||
361 | EAPI Evas_Object * | ||
362 | evas_object_top_get(const Evas *e) | ||
363 | { | ||
364 | Evas_Object *obj = NULL; | ||
365 | Eina_Inlist *list; | ||
366 | Evas_Layer *layer; | ||
367 | |||
368 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
369 | return NULL; | ||
370 | MAGIC_CHECK_END(); | ||
371 | |||
372 | list = EINA_INLIST_GET(e->layers); | ||
373 | if (!list) return NULL; | ||
374 | |||
375 | layer = (Evas_Layer *) list->last; | ||
376 | if (!layer) return NULL; | ||
377 | |||
378 | list = EINA_INLIST_GET(layer->objects); | ||
379 | if (!list) return NULL; | ||
380 | |||
381 | obj = (Evas_Object *) list->last; | ||
382 | if (!obj) return NULL; | ||
383 | |||
384 | while (obj) | ||
385 | { | ||
386 | if (!obj->delete_me) return obj; | ||
387 | obj = evas_object_below_get_internal(obj); | ||
388 | } | ||
389 | |||
390 | return obj; | ||
391 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_stats.c b/libraries/evas/src/lib/canvas/evas_stats.c new file mode 100644 index 0000000..cfb1a84 --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_stats.c | |||
@@ -0,0 +1,185 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | #include "evas_cs.h" | ||
4 | |||
5 | EAPI Eina_Bool | ||
6 | evas_cserve_want_get(void) | ||
7 | { | ||
8 | #ifdef EVAS_CSERVE | ||
9 | return evas_cserve_use_get(); | ||
10 | #endif | ||
11 | return 0; | ||
12 | } | ||
13 | |||
14 | EAPI Eina_Bool | ||
15 | evas_cserve_connected_get(void) | ||
16 | { | ||
17 | #ifdef EVAS_CSERVE | ||
18 | return evas_cserve_have_get(); | ||
19 | #endif | ||
20 | return 0; | ||
21 | } | ||
22 | |||
23 | EAPI Eina_Bool | ||
24 | evas_cserve_stats_get(Evas_Cserve_Stats *stats) | ||
25 | { | ||
26 | #ifdef EVAS_CSERVE | ||
27 | Op_Getstats_Reply st; | ||
28 | |||
29 | if (!evas_cserve_raw_stats_get(&st)) return 0; | ||
30 | if (!stats) return 1; | ||
31 | stats->saved_memory = st.saved_memory; | ||
32 | stats->wasted_memory = st.wasted_memory; | ||
33 | stats->saved_memory_peak = st.saved_memory_peak; | ||
34 | stats->wasted_memory_peak = st.wasted_memory_peak; | ||
35 | stats->saved_time_image_header_load = st.saved_time_image_header_load; | ||
36 | stats->saved_time_image_data_load = st.saved_time_image_data_load; | ||
37 | // may expand this in future | ||
38 | return 1; | ||
39 | #else | ||
40 | (void) stats; | ||
41 | return 0; | ||
42 | #endif | ||
43 | } | ||
44 | |||
45 | EAPI Eina_Bool | ||
46 | evas_cserve_image_cache_contents_get(Evas_Cserve_Image_Cache *cache) | ||
47 | { | ||
48 | #ifdef EVAS_CSERVE | ||
49 | Op_Getinfo_Reply *info; | ||
50 | unsigned char *p; | ||
51 | int i, j; | ||
52 | |||
53 | if (!(info = evas_cserve_raw_info_get())) return 0; | ||
54 | if (!cache) | ||
55 | { | ||
56 | free(info); | ||
57 | return 1; | ||
58 | } | ||
59 | cache->active.mem_total = info->active.mem_total; | ||
60 | cache->active.count = info->active.count; | ||
61 | cache->cached.mem_total = info->cached.mem_total; | ||
62 | cache->cached.count = info->cached.count; | ||
63 | cache->images = NULL; | ||
64 | j = info->active.count + info->cached.count; | ||
65 | p = (unsigned char *)info; | ||
66 | p += sizeof(Op_Getinfo_Reply); | ||
67 | for (i = 0; i < j; i++) | ||
68 | { | ||
69 | Evas_Cserve_Image *im; | ||
70 | Op_Getinfo_Item it; | ||
71 | char *file, *key; | ||
72 | |||
73 | memcpy(&it, p, sizeof(Op_Getinfo_Item)); | ||
74 | file = (char*) (p + sizeof(Op_Getinfo_Item)); | ||
75 | key = file + strlen(file) + 1; | ||
76 | im = calloc(1, sizeof(Evas_Cserve_Image)); | ||
77 | if (!im) continue; | ||
78 | if (file[0] != 0) | ||
79 | { | ||
80 | file = (char *)eina_stringshare_add(file); | ||
81 | if (!file) | ||
82 | { | ||
83 | free(im); | ||
84 | continue; | ||
85 | } | ||
86 | } | ||
87 | else | ||
88 | file = NULL; | ||
89 | if (key[0] != 0) | ||
90 | { | ||
91 | key = (char *)eina_stringshare_add(key); | ||
92 | if (!key) | ||
93 | { | ||
94 | if (file) eina_stringshare_del(file); | ||
95 | free(im); | ||
96 | continue; | ||
97 | } | ||
98 | } | ||
99 | else key = NULL; | ||
100 | cache->images = eina_list_append(cache->images, im); | ||
101 | im->file = file; | ||
102 | im->key = key; | ||
103 | im->w = it.w; | ||
104 | im->h = it.h; | ||
105 | im->cached_time = it.cached_time; | ||
106 | im->file_mod_time = it.file_mod_time; | ||
107 | im->file_checked_time = it.file_checked_time; | ||
108 | im->refcount = it.refcount; | ||
109 | im->data_refcount = it.data_refcount; | ||
110 | im->memory_footprint = it.memory_footprint; | ||
111 | im->head_load_time = it.head_load_time; | ||
112 | im->data_load_time = it.data_load_time; | ||
113 | im->active = it.active; | ||
114 | im->alpha = it.alpha; | ||
115 | im->data_loaded = it.data_loaded; | ||
116 | im->dead = it.dead; | ||
117 | im->useless = it.useless; | ||
118 | } | ||
119 | free(info); | ||
120 | return 1; | ||
121 | #else | ||
122 | (void) cache; | ||
123 | return 0; | ||
124 | #endif | ||
125 | } | ||
126 | |||
127 | EAPI void | ||
128 | evas_cserve_image_cache_contents_clean(Evas_Cserve_Image_Cache *cache) | ||
129 | { | ||
130 | #ifdef EVAS_CSERVE | ||
131 | Evas_Cserve_Image *im; | ||
132 | |||
133 | EINA_LIST_FREE(cache->images, im) | ||
134 | { | ||
135 | if (im->file) eina_stringshare_del(im->file); | ||
136 | if (im->key) eina_stringshare_del(im->key); | ||
137 | free(im); | ||
138 | } | ||
139 | #else | ||
140 | (void) cache; | ||
141 | #endif | ||
142 | } | ||
143 | |||
144 | EAPI Eina_Bool | ||
145 | evas_cserve_config_get(Evas_Cserve_Config *config) | ||
146 | { | ||
147 | #ifdef EVAS_CSERVE | ||
148 | Op_Getconfig_Reply conf; | ||
149 | |||
150 | if (!evas_cserve_raw_config_get(&conf)) return 0; | ||
151 | if (!config) return 1; | ||
152 | config->cache_max_usage = conf.cache_max_usage; | ||
153 | config->cache_item_timeout = conf.cache_item_timeout; | ||
154 | config->cache_item_timeout_check = conf.cache_item_timeout_check; | ||
155 | return 1; | ||
156 | #else | ||
157 | (void) config; | ||
158 | return 0; | ||
159 | #endif | ||
160 | } | ||
161 | |||
162 | EAPI Eina_Bool | ||
163 | evas_cserve_config_set(const Evas_Cserve_Config *config) | ||
164 | { | ||
165 | #ifdef EVAS_CSERVE | ||
166 | Op_Setconfig conf; | ||
167 | |||
168 | if (!config) return 1; | ||
169 | conf.cache_max_usage = config->cache_max_usage; | ||
170 | conf.cache_item_timeout = config->cache_item_timeout; | ||
171 | conf.cache_item_timeout_check = config->cache_item_timeout_check; | ||
172 | return evas_cserve_raw_config_set(&conf); | ||
173 | #else | ||
174 | (void) config; | ||
175 | return 0; | ||
176 | #endif | ||
177 | } | ||
178 | |||
179 | EAPI void | ||
180 | evas_cserve_disconnect(void) | ||
181 | { | ||
182 | #ifdef EVAS_CSERVE | ||
183 | evas_cserve_discon(); | ||
184 | #endif | ||
185 | } | ||
diff --git a/libraries/evas/src/lib/canvas/evas_touch_point.c b/libraries/evas/src/lib/canvas/evas_touch_point.c new file mode 100644 index 0000000..bdea73f --- /dev/null +++ b/libraries/evas/src/lib/canvas/evas_touch_point.c | |||
@@ -0,0 +1,110 @@ | |||
1 | #include "evas_common.h" | ||
2 | #include "evas_private.h" | ||
3 | |||
4 | void | ||
5 | _evas_touch_point_append(Evas *e, int id, Evas_Coord x, Evas_Coord y) | ||
6 | { | ||
7 | Evas_Coord_Touch_Point *point; | ||
8 | |||
9 | /* create new Evas_Coord_Touch_Point */ | ||
10 | point = (Evas_Coord_Touch_Point *)calloc(1, sizeof(Evas_Coord_Touch_Point)); | ||
11 | point->x = x; | ||
12 | point->y = y; | ||
13 | point->id = id; | ||
14 | point->state = EVAS_TOUCH_POINT_DOWN; | ||
15 | e->touch_points = eina_list_append(e->touch_points, point); | ||
16 | } | ||
17 | |||
18 | void | ||
19 | _evas_touch_point_update(Evas *e, int id, Evas_Coord x, Evas_Coord y, Evas_Touch_Point_State state) | ||
20 | { | ||
21 | Eina_List *l; | ||
22 | Evas_Coord_Touch_Point *point = NULL; | ||
23 | |||
24 | EINA_LIST_FOREACH(e->touch_points, l, point) | ||
25 | { | ||
26 | if (point->id == id) | ||
27 | { | ||
28 | point->x = x; | ||
29 | point->y = y; | ||
30 | point->state = state; | ||
31 | break; | ||
32 | } | ||
33 | } | ||
34 | } | ||
35 | |||
36 | void | ||
37 | _evas_touch_point_remove(Evas *e, int id) | ||
38 | { | ||
39 | Eina_List *l; | ||
40 | Evas_Coord_Touch_Point *point = NULL; | ||
41 | |||
42 | EINA_LIST_FOREACH(e->touch_points, l, point) | ||
43 | { | ||
44 | if (point->id == id) | ||
45 | { | ||
46 | e->touch_points = eina_list_remove(e->touch_points, point); | ||
47 | free(point); | ||
48 | break; | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
53 | EAPI unsigned int | ||
54 | evas_touch_point_list_count(Evas *e) | ||
55 | { | ||
56 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
57 | return 0; | ||
58 | MAGIC_CHECK_END(); | ||
59 | return eina_list_count(e->touch_points); | ||
60 | } | ||
61 | |||
62 | EAPI void | ||
63 | evas_touch_point_list_nth_xy_get(Evas *e, unsigned int n, Evas_Coord *x, Evas_Coord *y) | ||
64 | { | ||
65 | Evas_Coord_Touch_Point *point = NULL; | ||
66 | |||
67 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
68 | if (x) *x = 0; | ||
69 | if (y) *y = 0; | ||
70 | return; | ||
71 | MAGIC_CHECK_END(); | ||
72 | |||
73 | point = (Evas_Coord_Touch_Point *)eina_list_nth(e->touch_points, n); | ||
74 | if (!point) | ||
75 | { | ||
76 | if (x) *x = 0; | ||
77 | if (y) *y = 0; | ||
78 | return; | ||
79 | } | ||
80 | if (x) *x = point->x; | ||
81 | if (y) *y = point->y; | ||
82 | } | ||
83 | |||
84 | EAPI int | ||
85 | evas_touch_point_list_nth_id_get(Evas *e, unsigned int n) | ||
86 | { | ||
87 | Evas_Coord_Touch_Point *point = NULL; | ||
88 | |||
89 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
90 | return -1; | ||
91 | MAGIC_CHECK_END(); | ||
92 | |||
93 | point = (Evas_Coord_Touch_Point *)eina_list_nth(e->touch_points, n); | ||
94 | if (!point) return -1; | ||
95 | return point->id; | ||
96 | } | ||
97 | |||
98 | EAPI Evas_Touch_Point_State | ||
99 | evas_touch_point_list_nth_state_get(Evas *e, unsigned int n) | ||
100 | { | ||
101 | Evas_Coord_Touch_Point *point = NULL; | ||
102 | |||
103 | MAGIC_CHECK(e, Evas, MAGIC_EVAS); | ||
104 | return EVAS_TOUCH_POINT_CANCEL; | ||
105 | MAGIC_CHECK_END(); | ||
106 | |||
107 | point = (Evas_Coord_Touch_Point *)eina_list_nth(e->touch_points, n); | ||
108 | if (!point) return EVAS_TOUCH_POINT_CANCEL; | ||
109 | return point->state; | ||
110 | } | ||