win: Add background part to the win border

Use Efl.Part for window to manipulate the background.

Two part names are used in EDC:
 - elm.rect.background
 - elm.swallow.background

For apps the part name is only "background".

To set a solid color background (alpha is ok):
 efl_gfx_color_set(efl_part(win, "background"), r, g, b, a);

To set an image:
 efl_file_set(efl_part(win, "background"), "image.jpg", NULL);

To set an object:
 efl_content_set(efl_part(win, "background"), subobj);

The solid bg is invisible by default, will become visible and use
COPY render mode if a color is set. Standard window uses the
swallow part.

@feature
This commit is contained in:
Jean-Philippe Andre 2016-11-10 16:10:28 +09:00
parent cb172de3da
commit 0e52264ae0
10 changed files with 442 additions and 48 deletions

View File

@ -386,6 +386,10 @@ color_classes {
color: FN_COL_DISABLE;
desc: "Text of a disabled multibuttonentry item";
}
color_class { "elm/win/background";
color: 64 64 64 255;
desc: "Background color of a standard window";
}
// modules
color_class { name: "module_label";

View File

@ -787,6 +787,7 @@ group { name: "elm/border/base/default";
images.image: "win_shadow.png" COMP;
data.item: "shadow" "1";
parts {
/* opaque region of the window, to inform the compositor */
spacer { "elm.spacer.opaque";
desc {
rel1.to: "top";
@ -798,6 +799,16 @@ group { name: "elm/border/base/default";
}
desc { "max"; inherit: "shaded"; }
}
/* covers the entire client contents, including the main menu */
spacer { "elm.spacer.content";
required; // since 1.19
desc {
rel1.to: "top";
rel1.relative: 0.0 1.0;
rel2.to: "bottom";
rel2.relative: 1.0 0.0;
}
}
part { name: "shadow_clip"; type: RECT; mouse_events: 0;
description { state: "default";
rel1.to: "shadow";
@ -827,20 +838,42 @@ group { name: "elm/border/base/default";
rel2.to: "elm.swallow.client";
}
}
part { name: "client_clip"; type: RECT; mouse_events: 0;
description { state: "default" 0.0;
rect { "client_clip";
nomouse;
desc { "default";
rel1.to_y: "elm.swallow.client";
rel2.to_y: "elm.swallow.client";
}
/* description { state: "hidden" 0.0; */
/* inherit: "default"; */
/* visible: 0; */
/* } */
}
rect { "bg_clip";
nomouse;
desc { "default";
rel.to: "elm.spacer.content";
}
}
/* window background: solid color */
rect { "elm.rect.background";
required; // @since 1.19
clip: "bg_clip";
desc { "default";
color: 255 255 255 255;
color_class: "elm/win/background"; // FIXME: color_class naming scheme
visible: 0;
}
desc { "visible";
inherit: "default";
visible: 1;
}
}
/* window background: image */
swallow { "elm.swallow.background";
required; // @since 1.19
clip: "client_clip";
}
/* main menu */
rect { "menu_bg";
desc { "default";
color: 64 64 64 255; // FIXME color_class
color: 64 64 64 255; // FIXME: color_class
align: 0.5 0.0;
rel.to: "elm.swallow.menu";
}
@ -860,16 +893,7 @@ group { name: "elm/border/base/default";
fixed: 0 1;
}
}
/* covers the entire client contents, including the main menu */
spacer { "elm.spacer.content";
required: 1; // since 1.19
desc {
rel1.to: "top";
rel1.relative: 0.0 1.0;
rel2.to: "bottom";
rel2.relative: 1.0 0.0;
}
}
/* application contents */
part { name: "elm.swallow.client"; type: SWALLOW;
clip_to: "client_clip";
description { state: "default" 0.0;
@ -1383,6 +1407,16 @@ group { name: "elm/border/base/default";
action: STATE_SET "hidden" 0.0;
target: "shadow_clip";
}
program {
signal: "elm,state,background,solid,on"; source: "elm";
action: STATE_SET "visible" 0.0;
target: "elm.rect.background";
}
program {
signal: "elm,state,background,solid,off"; source: "elm";
action: STATE_SET "default" 0.0;
target: "elm.rect.background";
}
program {
signal: "elm,action,focus"; source: "elm";
action: STATE_SET "focused" 0.0;

View File

@ -121,6 +121,7 @@ elm_public_eolian_files = \
# Private classes (not exposed or shipped)
elm_private_eolian_files = \
lib/elementary/efl_ui_internal_text_interactive.eo \
lib/elementary/efl_ui_win_internal_part.eo \
$(NULL)
# Legacy classes - not part of public EO API

View File

@ -16,6 +16,7 @@ void test_access3(void *data, Evas_Object *obj, void *event_info);
void test_bg_plain(void *data, Evas_Object *obj, void *event_info);
void test_bg_image(void *data, Evas_Object *obj, void *event_info);
void test_bg_options(void *data, Evas_Object *obj, void *event_info);
void test_bg_window(void *data, Evas_Object *obj, void *event_info);
void test_icon(void *data, Evas_Object *obj, void *event_info);
void test_icon_transparent(void *data, Evas_Object *obj, void *event_info);
void test_icon_standard(void *data, Evas_Object *obj, void *event_info);
@ -629,6 +630,7 @@ add_tests:
ADD_TEST(NULL, "Window / Background", "Bg Plain", test_bg_plain);
ADD_TEST(NULL, "Window / Background", "Bg Image", test_bg_image);
ADD_TEST(NULL, "Window / Background", "Bg Options", test_bg_options);
ADD_TEST(NULL, "Window / Background", "Bg EOAPI (Efl.Ui.Win)", test_bg_window);
ADD_TEST(NULL, "Window / Background", "Window States", test_win_state);
ADD_TEST(NULL, "Window / Background", "Window States 2", test_win_state2);
ADD_TEST(NULL, "Window / Background", "Inwin", test_inwin);

View File

@ -268,3 +268,108 @@ test_bg_options(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *even
evas_object_resize(win, 320, 320);
evas_object_show(win);
}
static void
_colorsel_cb(void *data, const Efl_Event *ev)
{
Efl_Ui_Win *win = data;
int r, g, b, a;
// Solid color API
elm_colorselector_color_get(ev->object, &r, &g, &b, &a);
efl_gfx_color_set(efl_part(win, "background"), r, g, b, a);
efl_gfx_color_get(efl_part(win, "background"), &r, &g, &b, &a);
printf("bg color: %d %d %d %d\n", r, g, b, a);
fflush(stdout);
}
static void
_file_cb(void *data, const Efl_Event *ev)
{
Efl_Ui_Win *win = data;
const char *f, *k;
// File API
efl_file_get(efl_part(win, "background"), &f, &k);
if (f)
{
efl_file_set(efl_part(win, "background"), NULL, NULL);
}
else
{
efl_file_get(ev->object, &f, &k);
efl_file_set(efl_part(win, "background"), f, k);
}
}
static void
_image_cb(void *data, const Efl_Event *ev)
{
Efl_Ui_Win *win = data, *o;
const char *f, *k;
// Content API
if (efl_content_get(efl_part(win, "background")))
efl_content_set(efl_part(win, "background"), NULL);
else
{
efl_file_get(ev->object, &f, &k);
o = efl_add(EFL_UI_IMAGE_CLASS, win,
efl_ui_image_scale_type_set(efl_added, EFL_UI_IMAGE_SCALE_TYPE_FIT_OUTSIDE),
efl_file_set(efl_added, f, k)
);
efl_content_set(efl_part(win, "background"), o);
}
}
void
test_bg_window(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *win, *box;
char buf[PATH_MAX];
win = efl_add(EFL_UI_WIN_STANDARD_CLASS, NULL,
efl_text_set(efl_added, "Bg EOAPI (Efl.Ui.Win)"),
efl_ui_win_autodel_set(efl_added, EINA_TRUE),
efl_ui_win_alpha_set(efl_added, 1));
box = efl_add(EFL_UI_BOX_CLASS, win,
efl_gfx_size_hint_weight_set(efl_added, 1, 1),
efl_pack(win, efl_added), // FIXME / use content set
efl_gfx_visible_set(efl_added, 1));
efl_add(ELM_COLORSELECTOR_CLASS, win,
elm_colorselector_mode_set(efl_added, ELM_COLORSELECTOR_PALETTE),
elm_colorselector_palette_color_add(efl_added, 64, 64, 64, 255),
elm_colorselector_palette_color_add(efl_added, 255, 128, 128, 255),
elm_colorselector_palette_color_add(efl_added, 0, 64, 64, 64),
elm_colorselector_palette_color_add(efl_added, 0, 0, 0, 0),
efl_event_callback_add(efl_added, ELM_COLORSELECTOR_EVENT_COLOR_ITEM_SELECTED, _colorsel_cb, win),
efl_gfx_size_hint_weight_set(efl_added, 1.0, 1.0),
efl_pack(box, efl_added),
efl_gfx_visible_set(efl_added, 1)
);
snprintf(buf, sizeof(buf), "%s/images/plant_01.jpg", elm_app_data_dir_get());
efl_add(EFL_UI_IMAGE_CLASS, win,
efl_file_set(efl_added, buf, NULL),
efl_gfx_size_hint_min_set(efl_added, 64, 64),
efl_gfx_size_hint_weight_set(efl_added, 1.0, 1.0),
efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED, _file_cb, win),
efl_pack(box, efl_added),
efl_gfx_visible_set(efl_added, 1)
);
snprintf(buf, sizeof(buf), "%s/images/sky_04.jpg", elm_app_data_dir_get());
efl_add(EFL_UI_IMAGE_CLASS, win,
efl_file_set(efl_added, buf, NULL),
efl_gfx_size_hint_min_set(efl_added, 64, 64),
efl_gfx_size_hint_weight_set(efl_added, 1.0, 1.0),
efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED, _image_cb, win),
efl_pack(box, efl_added),
efl_gfx_visible_set(efl_added, 1)
);
efl_gfx_size_set(win, 300, 200);
efl_gfx_visible_set(win, 1);
}

View File

@ -20,6 +20,9 @@
#define EFL_INTERNAL_UNSTABLE
#include "interfaces/efl_common_internal.h"
#include "elm_part_helper.h"
#include "efl_ui_win_internal_part.eo.h"
#define MY_CLASS EFL_UI_WIN_CLASS
#define MY_CLASS_NAME "Efl.Ui.Win"
#define MY_CLASS_NAME_LEGACY "elm_win"
@ -99,6 +102,7 @@ struct _Efl_Ui_Win_Data
Evas_Object *img_obj, *frame_obj;
Eo *edje; /**< edje object for a window layout */
Eo *box;
Eo /* wref */ *bg, *std_bg;
Evas_Object *obj; /* The object itself */
#ifdef HAVE_ELEMENTARY_X
struct
@ -5176,23 +5180,10 @@ _efl_ui_win_noblank_get(Eo *obj EINA_UNUSED, Efl_Ui_Win_Data *pd)
EAPI Evas_Object *
elm_win_util_standard_add(const char *name, const char *title)
{
Evas_Object *win, *bg;
win = elm_win_add(NULL, name, ELM_WIN_BASIC);
if (!win) return NULL;
elm_win_title_set(win, title);
bg = elm_bg_add(win);
if (!bg)
{
evas_object_del(win);
return NULL;
}
evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(win, bg);
evas_object_show(bg);
return win;
return efl_add(EFL_UI_WIN_STANDARD_CLASS, NULL,
efl_text_set(efl_added, title),
efl_ui_win_name_set(efl_added, name)
);
}
EAPI Evas_Object *
@ -6382,6 +6373,256 @@ _efl_ui_win_efl_input_state_lock_enabled_get(Eo *obj EINA_UNUSED, Efl_Ui_Win_Dat
return evas_key_lock_is_set(m, name);
}
// See evas_inline.x
#define _EVAS_COLOR_CLAMP(x, y) do { \
if (x > y) { x = y; bad = 1; } \
if (x < 0) { x = 0; bad = 1; } } while (0)
#define EVAS_COLOR_SANITIZE(r, g, b, a) \
({ int bad = 0; \
_EVAS_COLOR_CLAMP(a, 255); \
_EVAS_COLOR_CLAMP(r, a); \
_EVAS_COLOR_CLAMP(g, a); \
_EVAS_COLOR_CLAMP(b, a); \
bad; })
/* Efl.Part APIs */
#define WIN_PART_ERR(part) ERR("No such part in window: '%s'. Supported parts are: 'background'.", part);
static void
_elm_win_bg_set(Efl_Ui_Win_Data *sd, Eo *bg, Eina_Bool std)
{
ELM_SAFE_DEL(sd->bg);
if (!bg)
{
efl_gfx_visible_set(sd->std_bg, 1);
return;
}
if (sd->frame_obj && edje_object_part_exists(sd->frame_obj, "elm.swallow.background"))
edje_object_part_swallow(sd->frame_obj, "elm.swallow.background", bg);
else
{
// Legacy theme or no CSD
Evas_Object *below = NULL;
Eina_Iterator *it;
// find lowest object in stack
it = evas_object_box_iterator_new(sd->box);
if (!eina_iterator_next(it, (void **) &below))
below = NULL;
eina_iterator_free(it);
elm_widget_sub_object_add(sd->obj, bg);
evas_object_box_prepend(sd->box, bg);
if (below) evas_object_stack_below(bg, below);
}
efl_gfx_visible_set(bg, 1);
efl_gfx_size_hint_align_set(bg, -1, -1);
efl_gfx_size_hint_weight_set(bg, 1, 1);
if (std)
{
efl_wref_add(bg, &sd->std_bg);
}
else
{
efl_gfx_visible_set(sd->std_bg, 0);
efl_wref_add(bg, &sd->bg);
}
}
void
_elm_win_standard_init(Eo *obj)
{
/* Support for elm_util_win_standard_add() and Efl.Ui.Win.Standard */
Efl_Ui_Win_Data *sd = efl_data_scope_get(obj, MY_CLASS);
ELM_SAFE_DEL(sd->bg);
if (sd->frame_obj && edje_object_part_exists(sd->frame_obj, "elm.rect.background"))
edje_object_signal_emit(sd->frame_obj, "elm,state,background,solid,on", "elm");
else
{
// Legacy theme or no CSD
Eo *bg = efl_add(ELM_BG_CLASS, obj);
_elm_win_bg_set(sd, bg, EINA_TRUE);
}
}
static Eina_Bool
_efl_ui_win_content_set(Eo *obj EINA_UNUSED, Efl_Ui_Win_Data *sd, const char *part, Eo *content)
{
if (!part) part = "content";
if (eina_streq(part, "content"))
{
// FIXME / TODO
return EINA_TRUE;
}
else if (eina_streq(part, "background"))
{
if (sd->bg == content) return EINA_TRUE;
_elm_win_bg_set(sd, content, EINA_FALSE);
return EINA_TRUE;
}
WIN_PART_ERR(part);
return EINA_FALSE;
}
static Efl_Canvas_Object *
_efl_ui_win_content_get(Eo *obj EINA_UNUSED, Efl_Ui_Win_Data *sd, const char *part)
{
if (!part) part = "content";
if (eina_streq(part, "content"))
{
// FIXME / TODO
return NULL;
}
else if (eina_streq(part, "background"))
return sd->bg;
WIN_PART_ERR(part);
return NULL;
}
static Efl_Canvas_Object *
_efl_ui_win_content_unset(Eo *obj, Efl_Ui_Win_Data *sd, const char *part)
{
Eo *content = _efl_ui_win_content_get(obj, sd, part);
if (!content) return NULL;
efl_ref(content);
_efl_ui_win_content_set(obj, sd, part, NULL);
return content;
}
static Eina_Bool
_efl_ui_win_part_color_set(Eo *obj, Efl_Ui_Win_Data *sd, const char *part, int r, int g, int b, int a)
{
if (eina_streq(part, "background"))
{
if (sd->frame_obj && edje_object_part_exists(sd->frame_obj, "elm.rect.background"))
{
// HACK: Force render mode of bg rect to COPY. This avoids render garbage.
Eo *bgrect = (Eo *) edje_object_part_object_get(sd->frame_obj, part);
efl_canvas_object_render_op_set(bgrect, EFL_GFX_RENDER_OP_COPY);
edje_object_color_class_set(sd->frame_obj, "elm/win/background", r, g, b, a, 0, 0, 0, 0, 0, 0, 0, 0);
edje_object_signal_emit(sd->frame_obj, "elm,state,background,solid,on", "elm");
}
else
{
// Legacy theme or no CSD
Eo *bg = efl_add(EFL_CANVAS_RECTANGLE_CLASS, obj,
efl_canvas_object_render_op_set(efl_added, EFL_GFX_RENDER_OP_COPY),
efl_gfx_color_set(efl_added, r, g, b, a));
_elm_win_bg_set(sd, bg, EINA_FALSE);
}
return EINA_TRUE;
}
WIN_PART_ERR(part);
return EINA_FALSE;
}
static Eina_Bool
_efl_ui_win_part_color_get(Eo *obj EINA_UNUSED, Efl_Ui_Win_Data *sd, const char *part, int *r, int *g, int *b, int *a)
{
if (eina_streq(part, "background"))
{
edje_object_color_class_get(sd->frame_obj, "elm/win/background", r, g, b, a, 0, 0, 0, 0, 0, 0, 0, 0);
return EINA_TRUE;
}
WIN_PART_ERR(part);
return EINA_FALSE;
}
static Eina_Bool
_efl_ui_win_part_file_set(Eo *obj, Efl_Ui_Win_Data *sd, const char *part, const char *file, const char *key)
{
if (eina_streq(part, "background"))
{
Eina_Bool ok = EINA_TRUE;
Eo *bg = NULL;
if (file)
{
bg = efl_add(EFL_UI_IMAGE_CLASS, obj);
efl_ui_image_scale_type_set(bg, EFL_UI_IMAGE_SCALE_TYPE_FIT_OUTSIDE);
ok = efl_file_set(bg, file, key);
if (!ok) ELM_SAFE_DEL(bg);
_elm_win_bg_set(sd, bg, EINA_FALSE);
}
else
{
_elm_win_standard_init(obj);
}
return ok;
}
WIN_PART_ERR(part);
return EINA_FALSE;
}
static Eina_Bool
_efl_ui_win_part_file_get(Eo *obj, Efl_Ui_Win_Data *sd, const char *part, const char **file, const char **key)
{
if (file) *file = NULL;
if (key) *key = NULL;
if (eina_streq(part, "background"))
{
const Eo *bg = _efl_ui_win_content_get(obj, sd, "background");
efl_file_get(bg, file, key);
return EINA_TRUE;
}
WIN_PART_ERR(part);
return EINA_FALSE;
}
/* Efl.Part begin */
static void
_efl_ui_win_internal_part_efl_gfx_color_set(Eo *obj, Elm_Part_Data *pd, int r, int g, int b, int a)
{
if (EVAS_COLOR_SANITIZE(r, g, b, a))
ERR("Evas only handles premultiplied colors (0 <= R,G,B <= A <= 255)");
_efl_ui_win_part_color_set(pd->obj, pd->sd, pd->part, r, g, b, a);
ELM_PART_RETURN_VOID;
}
static void
_efl_ui_win_internal_part_efl_gfx_color_get(Eo *obj, Elm_Part_Data *pd, int *r, int *g, int *b, int *a)
{
_efl_ui_win_part_color_get(pd->obj, pd->sd, pd->part, r, g, b, a);
ELM_PART_RETURN_VOID;
}
static Eina_Bool
_efl_ui_win_internal_part_efl_file_file_set(Eo *obj, Elm_Part_Data *pd, const char *file, const char *key)
{
ELM_PART_RETURN_VAL(_efl_ui_win_part_file_set(pd->obj, pd->sd, pd->part, file, key));
}
static void
_efl_ui_win_internal_part_efl_file_file_get(Eo *obj, Elm_Part_Data *pd, const char **file, const char **key)
{
_efl_ui_win_part_file_get(pd->obj, pd->sd, pd->part, file, key);
ELM_PART_RETURN_VOID;
}
ELM_PART_IMPLEMENT(efl_ui_win, EFL_UI_WIN, Efl_Ui_Win_Data, Elm_Part_Data)
ELM_PART_IMPLEMENT_CONTENT_SET(efl_ui_win, EFL_UI_WIN, Efl_Ui_Win_Data, Elm_Part_Data)
ELM_PART_IMPLEMENT_CONTENT_GET(efl_ui_win, EFL_UI_WIN, Efl_Ui_Win_Data, Elm_Part_Data)
ELM_PART_IMPLEMENT_CONTENT_UNSET(efl_ui_win, EFL_UI_WIN, Efl_Ui_Win_Data, Elm_Part_Data)
#include "efl_ui_win_internal_part.eo.c"
/* Efl.Part end */
#ifndef EFL_TEAMWORK_VERSION
# define EFL_TEAMWORK_VERSION 2
#endif

View File

@ -174,7 +174,8 @@ enum Efl.Ui.Win.Move_Resize_Mode
class Efl.Ui.Win (Elm.Widget, Efl.Canvas, Elm.Interface.Atspi.Window,
Elm.Interface.Atspi_Widget_Action, Efl.Pack,
Efl.Input.State, Efl.Input.Interface, Efl.Screen,
Efl.Gfx.Size.Hint, Efl.Text, Efl.Config.Global)
Efl.Gfx.Size.Hint, Efl.Text, Efl.Config.Global,
Efl.Part)
{
[[Efl UI window class]]
legacy_prefix: elm_win;
@ -935,6 +936,7 @@ class Efl.Ui.Win (Elm.Widget, Efl.Canvas, Elm.Interface.Atspi.Window,
Efl.Canvas.object_top_at_xy_get;
Efl.Canvas.objects_in_rectangle_get;
Efl.Canvas.object_top_in_rectangle_get;
Efl.Part.part;
}
constructors {
.name;

View File

@ -0,0 +1,14 @@
class Efl.Ui.Win.Internal.Part (Efl.Object, Efl.Container, Efl.Gfx, Efl.File)
{
data: Elm_Part_Data;
implements {
Efl.Object.destructor;
Efl.Container.content.set;
Efl.Container.content.get;
Efl.Container.content_unset;
Efl.Gfx.color.set;
Efl.Gfx.color.get;
Efl.File.file.set;
Efl.File.file.get;
}
}

View File

@ -16,20 +16,9 @@ EOLIAN static Eo *
_efl_ui_win_standard_efl_object_finalize(Eo *obj, void *pd EINA_UNUSED)
{
obj = efl_finalize(efl_super(obj, MY_CLASS));
if (!obj)
return NULL;
Evas_Object *bg = efl_add(ELM_BG_CLASS, obj);
if (!bg)
{
ERR("Cannot create background.");
evas_object_del(obj);
return NULL;
}
efl_gfx_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
efl_pack(obj, bg);
efl_gfx_visible_set(bg, EINA_TRUE);
if (!obj) return NULL;
_elm_win_standard_init(obj);
return obj;
}

View File

@ -174,6 +174,7 @@ extern const char *_elm_engines[];
#define ELM_SAFE_FREE(_h, _fn) do { _fn((void*)_h); _h = NULL; } while (0)
#define ELM_SAFE_DEL(_h) do { efl_del(_h); _h = NULL; } while (0)
#define ELM_PRIV_STATIC_VARIABLE_DECLARE(name, signal, type) \
static const char name[] = signal;
@ -381,6 +382,7 @@ void _elm_win_rescale(Elm_Theme *th,
void _elm_win_access(Eina_Bool is_access);
void _elm_win_translate(void);
void _elm_win_focus_reconfigure(void);
void _elm_win_standard_init(Eo *win);
Ecore_X_Window _elm_ee_xwin_get(const Ecore_Evas *ee);