Changes to Brush texture workflow
This changes how textures are accessed from Brushes, with the intention of simplifying the workflow, and reducing the amount of clicking. Rather than the previous texture slots (which didn't work as a stack anyway), brushes now have a single texture linked. Rather than taking time having to set up your slots in advance, you can now select and change textures directly as you sculpt/paint on the fly. For complex brushes, node textures can be used, or for fast access, it's easy to make a duplicate of your brush with the texture you like and assign a hotkey. Brush textures can now be chosen from a new Textures panel in the brush tool properties - click on the thumbnail to open a texture selector. This is done using a new variation on the ID template - the number of rows and columns to display in the popup can be customised in the UI scripts.
This commit is contained in:
		@@ -87,13 +87,15 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel):
 | 
			
		||||
    def draw(self, context):
 | 
			
		||||
        layout = self.layout
 | 
			
		||||
 | 
			
		||||
        space = context.space_data
 | 
			
		||||
        tex = context.texture
 | 
			
		||||
        wide_ui = context.region.width > narrowui
 | 
			
		||||
        idblock = context_tex_datablock(context)
 | 
			
		||||
        tex_collection = space.pin_id == None and type(idblock) != bpy.types.Brush
 | 
			
		||||
 | 
			
		||||
        space = context.space_data
 | 
			
		||||
        
 | 
			
		||||
        if idblock:
 | 
			
		||||
 | 
			
		||||
        if tex_collection:
 | 
			
		||||
            row = layout.row()
 | 
			
		||||
 | 
			
		||||
            row.template_list(idblock, "textures", idblock, "active_texture_index", rows=2)
 | 
			
		||||
@@ -102,15 +104,22 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel):
 | 
			
		||||
            col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
 | 
			
		||||
            col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        if wide_ui:
 | 
			
		||||
            split = layout.split(percentage=0.65)
 | 
			
		||||
            if idblock:
 | 
			
		||||
                split.template_ID(idblock, "active_texture", new="texture.new")
 | 
			
		||||
            elif tex:
 | 
			
		||||
                split.template_ID(space, "pin_id")
 | 
			
		||||
            col = split.column()
 | 
			
		||||
        else:
 | 
			
		||||
            layout.template_ID(idblock, "active_texture", new="texture.new")
 | 
			
		||||
            col = layout.column()
 | 
			
		||||
            
 | 
			
		||||
        if tex_collection:
 | 
			
		||||
            col.template_ID(idblock, "active_texture", new="texture.new")
 | 
			
		||||
        elif idblock:
 | 
			
		||||
            col.template_ID(idblock, "texture", new="texture.new")
 | 
			
		||||
        
 | 
			
		||||
        if space.pin_id:
 | 
			
		||||
            col.template_ID(space, "pin_id")
 | 
			
		||||
        
 | 
			
		||||
        if wide_ui:
 | 
			
		||||
            col = split.column()
 | 
			
		||||
        
 | 
			
		||||
        if (not space.pin_id) and (
 | 
			
		||||
            context.sculpt_object or
 | 
			
		||||
@@ -118,7 +127,7 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel):
 | 
			
		||||
            context.weight_paint_object or
 | 
			
		||||
            context.texture_paint_object):
 | 
			
		||||
 | 
			
		||||
            split.prop(space, "brush_texture", text="Brush", toggle=True)
 | 
			
		||||
            col.prop(space, "brush_texture", text="Brush", toggle=True)
 | 
			
		||||
 | 
			
		||||
        if tex:
 | 
			
		||||
            layout.prop(tex, "use_nodes")
 | 
			
		||||
@@ -268,6 +277,10 @@ class TEXTURE_PT_influence(TextureSlotPanel):
 | 
			
		||||
    bl_label = "Influence"
 | 
			
		||||
 | 
			
		||||
    def poll(self, context):
 | 
			
		||||
        idblock = context_tex_datablock(context)
 | 
			
		||||
        if type(idblock) == bpy.types.Brush:
 | 
			
		||||
            return False
 | 
			
		||||
    
 | 
			
		||||
        return context.texture_slot
 | 
			
		||||
 | 
			
		||||
    def draw(self, context):
 | 
			
		||||
 
 | 
			
		||||
@@ -624,6 +624,29 @@ class VIEW3D_PT_tools_brush(PaintPanel):
 | 
			
		||||
            #row.prop(brush, "jitter", slider=True)
 | 
			
		||||
            #row.prop(brush, "use_jitter_pressure", toggle=True, text="")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class VIEW3D_PT_tools_brush_texture(PaintPanel):
 | 
			
		||||
    bl_label = "Texture"
 | 
			
		||||
    bl_default_closed = True
 | 
			
		||||
 | 
			
		||||
    def poll(self, context):
 | 
			
		||||
        settings = self.paint_settings(context)
 | 
			
		||||
        return (settings and settings.brush and (context.sculpt_object or
 | 
			
		||||
                             context.texture_paint_object))
 | 
			
		||||
 | 
			
		||||
    def draw(self, context):
 | 
			
		||||
        layout = self.layout
 | 
			
		||||
 | 
			
		||||
        settings = self.paint_settings(context)
 | 
			
		||||
        brush = settings.brush
 | 
			
		||||
        tex_slot = brush.texture_slot
 | 
			
		||||
        
 | 
			
		||||
        col = layout.column()
 | 
			
		||||
        
 | 
			
		||||
        col.template_ID_preview(brush, "texture", new="texture.new", rows=2, cols=4)
 | 
			
		||||
        
 | 
			
		||||
        col.row().prop(tex_slot, "map_mode", expand=True)
 | 
			
		||||
        
 | 
			
		||||
class VIEW3D_PT_tools_brush_tool(PaintPanel):
 | 
			
		||||
    bl_label = "Tool"
 | 
			
		||||
    bl_default_closed = True
 | 
			
		||||
@@ -975,6 +998,7 @@ bpy.types.register(VIEW3D_PT_tools_latticeedit)
 | 
			
		||||
bpy.types.register(VIEW3D_PT_tools_posemode)
 | 
			
		||||
bpy.types.register(VIEW3D_PT_tools_posemode_options)
 | 
			
		||||
bpy.types.register(VIEW3D_PT_tools_brush)
 | 
			
		||||
bpy.types.register(VIEW3D_PT_tools_brush_texture)
 | 
			
		||||
bpy.types.register(VIEW3D_PT_tools_brush_tool)
 | 
			
		||||
bpy.types.register(VIEW3D_PT_tools_brush_stroke)
 | 
			
		||||
bpy.types.register(VIEW3D_PT_tools_brush_curve)
 | 
			
		||||
 
 | 
			
		||||
@@ -100,18 +100,10 @@ Brush *add_brush(const char *name)
 | 
			
		||||
Brush *copy_brush(Brush *brush)
 | 
			
		||||
{
 | 
			
		||||
	Brush *brushn;
 | 
			
		||||
	MTex *mtex;
 | 
			
		||||
	int a;
 | 
			
		||||
	
 | 
			
		||||
	brushn= copy_libblock(brush);
 | 
			
		||||
 | 
			
		||||
	for(a=0; a<MAX_MTEX; a++) {
 | 
			
		||||
		mtex= brush->mtex[a];
 | 
			
		||||
		if(mtex) {
 | 
			
		||||
			brushn->mtex[a]= MEM_dupallocN(mtex);
 | 
			
		||||
			if(mtex->tex) id_us_plus((ID*)mtex->tex);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(brush->mtex.tex) id_us_plus((ID*)brush->mtex.tex);
 | 
			
		||||
	
 | 
			
		||||
	brushn->curve= curvemapping_copy(brush->curve);
 | 
			
		||||
 | 
			
		||||
@@ -127,16 +119,7 @@ Brush *copy_brush(Brush *brush)
 | 
			
		||||
/* not brush itself */
 | 
			
		||||
void free_brush(Brush *brush)
 | 
			
		||||
{
 | 
			
		||||
	MTex *mtex;
 | 
			
		||||
	int a;
 | 
			
		||||
 | 
			
		||||
	for(a=0; a<MAX_MTEX; a++) {
 | 
			
		||||
		mtex= brush->mtex[a];
 | 
			
		||||
		if(mtex) {
 | 
			
		||||
			if(mtex->tex) mtex->tex->id.us--;
 | 
			
		||||
			MEM_freeN(mtex);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if(brush->mtex.tex) brush->mtex.tex->id.us--;
 | 
			
		||||
	
 | 
			
		||||
	curvemapping_free(brush->curve);
 | 
			
		||||
}
 | 
			
		||||
@@ -295,8 +278,8 @@ void brush_curve_preset(Brush *b, BrushCurvePreset preset)
 | 
			
		||||
 | 
			
		||||
static MTex *brush_active_texture(Brush *brush)
 | 
			
		||||
{
 | 
			
		||||
	if(brush && brush->texact >= 0)
 | 
			
		||||
		return brush->mtex[brush->texact];
 | 
			
		||||
	if(brush)
 | 
			
		||||
		return &brush->mtex;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -304,8 +287,7 @@ int brush_texture_set_nr(Brush *brush, int nr)
 | 
			
		||||
{
 | 
			
		||||
	ID *idtest, *id=NULL;
 | 
			
		||||
 | 
			
		||||
	if(brush->mtex[brush->texact])
 | 
			
		||||
		id= (ID *)brush->mtex[brush->texact]->tex;
 | 
			
		||||
	id= (ID *)brush->mtex.tex;
 | 
			
		||||
 | 
			
		||||
	idtest= (ID*)BLI_findlink(&G.main->tex, nr-1);
 | 
			
		||||
	if(idtest==0) { /* new tex */
 | 
			
		||||
@@ -316,13 +298,7 @@ int brush_texture_set_nr(Brush *brush, int nr)
 | 
			
		||||
	if(idtest!=id) {
 | 
			
		||||
		brush_texture_delete(brush);
 | 
			
		||||
 | 
			
		||||
		if(brush->mtex[brush->texact]==NULL) {
 | 
			
		||||
			brush->mtex[brush->texact]= add_mtex();
 | 
			
		||||
			brush->mtex[brush->texact]->r = 1.0f;
 | 
			
		||||
			brush->mtex[brush->texact]->g = 1.0f;
 | 
			
		||||
			brush->mtex[brush->texact]->b = 1.0f;
 | 
			
		||||
		}
 | 
			
		||||
		brush->mtex[brush->texact]->tex= (Tex*)idtest;
 | 
			
		||||
		brush->mtex.tex= (Tex*)idtest;
 | 
			
		||||
		id_us_plus(idtest);
 | 
			
		||||
 | 
			
		||||
		return 1;
 | 
			
		||||
@@ -333,16 +309,10 @@ int brush_texture_set_nr(Brush *brush, int nr)
 | 
			
		||||
 | 
			
		||||
int brush_texture_delete(Brush *brush)
 | 
			
		||||
{
 | 
			
		||||
	if(brush->mtex[brush->texact]) {
 | 
			
		||||
		if(brush->mtex[brush->texact]->tex)
 | 
			
		||||
			brush->mtex[brush->texact]->tex->id.us--;
 | 
			
		||||
		MEM_freeN(brush->mtex[brush->texact]);
 | 
			
		||||
		brush->mtex[brush->texact]= NULL;
 | 
			
		||||
	if(brush->mtex.tex)
 | 
			
		||||
		brush->mtex.tex->id.us--;
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int brush_clone_image_set_nr(Brush *brush, int nr)
 | 
			
		||||
@@ -383,7 +353,7 @@ void brush_check_exists(Brush **brush, const char *name)
 | 
			
		||||
/* Brush Sampling */
 | 
			
		||||
void brush_sample_tex(Brush *brush, float *xy, float *rgba)
 | 
			
		||||
{
 | 
			
		||||
	MTex *mtex= brush->mtex[brush->texact];
 | 
			
		||||
	MTex *mtex= &brush->mtex;
 | 
			
		||||
 | 
			
		||||
	if (mtex && mtex->tex) {
 | 
			
		||||
		float co[3], tin, tr, tg, tb, ta;
 | 
			
		||||
@@ -741,7 +711,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, float *pos)
 | 
			
		||||
{
 | 
			
		||||
	Brush *brush= painter->brush;
 | 
			
		||||
	BrushPainterCache *cache= &painter->cache;
 | 
			
		||||
	MTex *mtex= brush->mtex[brush->texact];
 | 
			
		||||
	MTex *mtex= &brush->mtex;
 | 
			
		||||
	int size;
 | 
			
		||||
	short flt;
 | 
			
		||||
 | 
			
		||||
@@ -976,7 +946,7 @@ float brush_curve_strength(Brush *br, float p, const float len)
 | 
			
		||||
unsigned int *brush_gen_texture_cache(Brush *br, int half_side)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int *texcache = NULL;
 | 
			
		||||
	MTex *mtex = br->mtex[br->texact];
 | 
			
		||||
	MTex *mtex = &br->mtex;
 | 
			
		||||
	TexResult texres;
 | 
			
		||||
	int hasrgb, ix, iy;
 | 
			
		||||
	int side = half_side * 2;
 | 
			
		||||
 
 | 
			
		||||
@@ -703,12 +703,10 @@ void make_local_texture(Tex *tex)
 | 
			
		||||
	}
 | 
			
		||||
	br= G.main->brush.first;
 | 
			
		||||
	while(br) {
 | 
			
		||||
		for(a=0; a<MAX_MTEX; a++) {
 | 
			
		||||
			if(br->mtex[a] && br->mtex[a]->tex==tex) {
 | 
			
		||||
		if(br->mtex.tex==tex) {
 | 
			
		||||
			if(br->id.lib) lib= 1;
 | 
			
		||||
			else local= 1;
 | 
			
		||||
		}
 | 
			
		||||
		}
 | 
			
		||||
		br= br->id.next;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
@@ -762,15 +760,13 @@ void make_local_texture(Tex *tex)
 | 
			
		||||
		}
 | 
			
		||||
		br= G.main->brush.first;
 | 
			
		||||
		while(br) {
 | 
			
		||||
			for(a=0; a<MAX_MTEX; a++) {
 | 
			
		||||
				if(br->mtex[a] && br->mtex[a]->tex==tex) {
 | 
			
		||||
			if(br->mtex.tex==tex) {
 | 
			
		||||
				if(br->id.lib==0) {
 | 
			
		||||
						br->mtex[a]->tex= texn;
 | 
			
		||||
					br->mtex.tex= texn;
 | 
			
		||||
					texn->id.us++;
 | 
			
		||||
					tex->id.us--;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			}
 | 
			
		||||
			br= br->id.next;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -904,10 +900,6 @@ int give_active_mtex(ID *id, MTex ***mtex_ar, short *act)
 | 
			
		||||
		*mtex_ar=		((Lamp *)id)->mtex;
 | 
			
		||||
		if(act) *act=	(((Lamp *)id)->texact);
 | 
			
		||||
		break;
 | 
			
		||||
	case ID_BR:
 | 
			
		||||
		*mtex_ar=		((Brush *)id)->mtex;
 | 
			
		||||
		if(act) *act=	(((Brush *)id)->texact);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		*mtex_ar = NULL;
 | 
			
		||||
		if(act) *act=	0;
 | 
			
		||||
@@ -932,9 +924,6 @@ void set_active_mtex(ID *id, short act)
 | 
			
		||||
	case ID_LA:
 | 
			
		||||
		((Lamp *)id)->texact= act;
 | 
			
		||||
		break;
 | 
			
		||||
	case ID_BR:
 | 
			
		||||
		((Brush *)id)->texact= act;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1016,35 +1005,18 @@ void set_current_world_texture(World *wo, Tex *newtex)
 | 
			
		||||
 | 
			
		||||
Tex *give_current_brush_texture(Brush *br)
 | 
			
		||||
{
 | 
			
		||||
	MTex *mtex= NULL;
 | 
			
		||||
	Tex *tex= NULL;
 | 
			
		||||
 | 
			
		||||
	if(br) {
 | 
			
		||||
		mtex= br->mtex[(int)(br->texact)];
 | 
			
		||||
		if(mtex) tex= mtex->tex;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tex;
 | 
			
		||||
	return br->mtex.tex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void set_current_brush_texture(Brush *br, Tex *newtex)
 | 
			
		||||
{
 | 
			
		||||
	int act= br->texact;
 | 
			
		||||
 | 
			
		||||
	if(br->mtex[act] && br->mtex[act]->tex)
 | 
			
		||||
		id_us_min(&br->mtex[act]->tex->id);
 | 
			
		||||
	if(br->mtex.tex)
 | 
			
		||||
		id_us_min(&br->mtex.tex->id);
 | 
			
		||||
 | 
			
		||||
	if(newtex) {
 | 
			
		||||
		if(!br->mtex[act])
 | 
			
		||||
			br->mtex[act]= add_mtex();
 | 
			
		||||
		
 | 
			
		||||
		br->mtex[act]->tex= newtex;
 | 
			
		||||
		br->mtex.tex= newtex;
 | 
			
		||||
		id_us_plus(&newtex->id);
 | 
			
		||||
	}
 | 
			
		||||
	else if(br->mtex[act]) {
 | 
			
		||||
		MEM_freeN(br->mtex[act]);
 | 
			
		||||
		br->mtex[act]= NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ------------------------------------------------------------------------- */
 | 
			
		||||
 
 | 
			
		||||
@@ -1532,22 +1532,13 @@ static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
 | 
			
		||||
static void lib_link_brush(FileData *fd, Main *main)
 | 
			
		||||
{
 | 
			
		||||
	Brush *brush;
 | 
			
		||||
	MTex *mtex;
 | 
			
		||||
	int a;
 | 
			
		||||
	
 | 
			
		||||
	/* only link ID pointers */
 | 
			
		||||
	for(brush= main->brush.first; brush; brush= brush->id.next) {
 | 
			
		||||
		if(brush->id.flag & LIB_NEEDLINK) {
 | 
			
		||||
			brush->id.flag -= LIB_NEEDLINK;
 | 
			
		||||
 | 
			
		||||
			brush->clone.image= newlibadr_us(fd, brush->id.lib, brush->clone.image);
 | 
			
		||||
			
 | 
			
		||||
			for(a=0; a<MAX_MTEX; a++) {
 | 
			
		||||
				mtex= brush->mtex[a];
 | 
			
		||||
				if(mtex)
 | 
			
		||||
					mtex->tex= newlibadr_us(fd, brush->id.lib, mtex->tex);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			brush->mtex.tex= newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
 | 
			
		||||
			brush->clone.image= newlibadr_us(fd, brush->id.lib, brush->clone.image);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -1556,10 +1547,6 @@ static void lib_link_brush(FileData *fd, Main *main)
 | 
			
		||||
static void direct_link_brush(FileData *fd, Brush *brush)
 | 
			
		||||
{
 | 
			
		||||
	/* brush itself has been read */
 | 
			
		||||
	int a;
 | 
			
		||||
 | 
			
		||||
	for(a=0; a<MAX_MTEX; a++)
 | 
			
		||||
		brush->mtex[a]= newdataadr(fd, brush->mtex[a]);
 | 
			
		||||
 | 
			
		||||
	/* fallof curve */
 | 
			
		||||
	brush->curve= newdataadr(fd, brush->curve);
 | 
			
		||||
@@ -10336,6 +10323,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
 | 
			
		||||
	if (1) {
 | 
			
		||||
		Scene *sce;
 | 
			
		||||
		Object *ob;
 | 
			
		||||
		Brush *brush;
 | 
			
		||||
		
 | 
			
		||||
		/* game engine changes */
 | 
			
		||||
		for(sce = main->scene.first; sce; sce = sce->id.next) {
 | 
			
		||||
@@ -10393,6 +10381,11 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
 | 
			
		||||
				avs->path_step= arm->pathsize;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		/* brush texture changes */
 | 
			
		||||
		for (brush= main->brush.first; brush; brush= brush->id.next) {
 | 
			
		||||
			default_mtex(&brush->mtex);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
 | 
			
		||||
@@ -10891,11 +10884,7 @@ static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
 | 
			
		||||
 | 
			
		||||
static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
 | 
			
		||||
{
 | 
			
		||||
	int a;
 | 
			
		||||
 | 
			
		||||
	for(a=0; a<MAX_MTEX; a++)
 | 
			
		||||
		if(brush->mtex[a])
 | 
			
		||||
			expand_doit(fd, mainvar, brush->mtex[a]->tex);
 | 
			
		||||
	expand_doit(fd, mainvar, brush->mtex.tex);
 | 
			
		||||
	expand_doit(fd, mainvar, brush->clone.image);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2317,15 +2317,11 @@ static void write_nodetrees(WriteData *wd, ListBase *idbase)
 | 
			
		||||
static void write_brushes(WriteData *wd, ListBase *idbase)
 | 
			
		||||
{
 | 
			
		||||
	Brush *brush;
 | 
			
		||||
	int a;
 | 
			
		||||
	
 | 
			
		||||
	for(brush=idbase->first; brush; brush= brush->id.next) {
 | 
			
		||||
		if(brush->id.us>0 || wd->current) {
 | 
			
		||||
			writestruct(wd, ID_BR, "Brush", 1, brush);
 | 
			
		||||
			if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd);
 | 
			
		||||
			for(a=0; a<MAX_MTEX; a++)
 | 
			
		||||
				if(brush->mtex[a])
 | 
			
		||||
					writestruct(wd, DATA, "MTex", 1, brush->mtex[a]);
 | 
			
		||||
			
 | 
			
		||||
			if(brush->curve)
 | 
			
		||||
				write_curvemapping(wd, brush->curve);
 | 
			
		||||
 
 | 
			
		||||
@@ -126,11 +126,12 @@ typedef struct uiLayout uiLayout;
 | 
			
		||||
#define UI_TEXT_LEFT	64
 | 
			
		||||
#define UI_ICON_LEFT	128
 | 
			
		||||
#define UI_ICON_SUBMENU	256
 | 
			
		||||
#define UI_ICON_PREVIEW	512
 | 
			
		||||
	/* control for button type block */
 | 
			
		||||
#define UI_MAKE_TOP		512
 | 
			
		||||
#define UI_MAKE_DOWN	1024
 | 
			
		||||
#define UI_MAKE_LEFT	2048
 | 
			
		||||
#define UI_MAKE_RIGHT	4096
 | 
			
		||||
#define UI_MAKE_TOP		1024
 | 
			
		||||
#define UI_MAKE_DOWN	2048
 | 
			
		||||
#define UI_MAKE_LEFT	4096
 | 
			
		||||
#define UI_MAKE_RIGHT	8192
 | 
			
		||||
 | 
			
		||||
	/* button align flag, for drawing groups together */
 | 
			
		||||
#define UI_BUT_ALIGN		(15<<14)
 | 
			
		||||
@@ -427,6 +428,7 @@ struct PointerRNA *uiButGetOperatorPtrRNA(uiBut *but);
 | 
			
		||||
#define UI_ID_FAKE_USER		256
 | 
			
		||||
#define UI_ID_PIN			512
 | 
			
		||||
#define UI_ID_BROWSE_RENDER	1024
 | 
			
		||||
#define UI_ID_PREVIEWS		2048
 | 
			
		||||
#define UI_ID_FULL			(UI_ID_RENAME|UI_ID_BROWSE|UI_ID_ADD_NEW|UI_ID_OPEN|UI_ID_ALONE|UI_ID_DELETE|UI_ID_LOCAL)
 | 
			
		||||
 | 
			
		||||
typedef void (*uiIDPoinFuncFP)(struct bContext *C, char *str, struct ID **idpp);
 | 
			
		||||
@@ -451,7 +453,7 @@ uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg,
 | 
			
		||||
uiBut *uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip);
 | 
			
		||||
uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *keypoin, short *modkeypoin, char *tip);
 | 
			
		||||
 | 
			
		||||
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, char *tip);
 | 
			
		||||
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, float a1, float a2, char *tip);
 | 
			
		||||
 | 
			
		||||
void uiBlockPickerButtons(struct uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval);
 | 
			
		||||
void uiBlockColorbandButtons(struct uiBlock *block, struct ColorBand *coba, struct rctf *butr, int event);
 | 
			
		||||
@@ -641,6 +643,8 @@ void uiTemplateHeader(uiLayout *layout, struct bContext *C, int menus);
 | 
			
		||||
void uiTemplateDopeSheetFilter(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
 | 
			
		||||
void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
 | 
			
		||||
	char *newop, char *openop, char *unlinkop);
 | 
			
		||||
void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
 | 
			
		||||
	char *newop, char *openop, char *unlinkop, int rows, int cols);
 | 
			
		||||
void uiTemplateAnyID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, 
 | 
			
		||||
	char *proptypename, char *text);
 | 
			
		||||
void uiTemplatePathBuilder(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, 
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,9 @@ int UI_icon_get_width(int icon_id);
 | 
			
		||||
int UI_icon_get_height(int icon_id);
 | 
			
		||||
 | 
			
		||||
void UI_icon_draw(float x, float y, int icon_id);
 | 
			
		||||
void UI_icon_draw_preview(float x, float y, int icon_id, int nocreate);
 | 
			
		||||
void UI_icon_draw_preview(float x, float y, int icon_id);
 | 
			
		||||
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect);
 | 
			
		||||
void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size);
 | 
			
		||||
 | 
			
		||||
void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha);
 | 
			
		||||
void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, float *rgb);
 | 
			
		||||
 
 | 
			
		||||
@@ -3171,9 +3171,10 @@ uiBut *uiDefHotKeyevtButS(uiBlock *block, int retval, char *str, short x1, short
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* arg is pointer to string/name, use uiButSetSearchFunc() below to make this work */
 | 
			
		||||
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, char *tip)
 | 
			
		||||
/* here a1 and a2, if set, control thumbnail preview rows/cols */
 | 
			
		||||
uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxlen, short x1, short y1, short x2, short y2, float a1, float a2, char *tip)
 | 
			
		||||
{
 | 
			
		||||
	uiBut *but= ui_def_but(block, SEARCH_MENU, retval, "", x1, y1, x2, y2, arg, 0.0, maxlen, 0.0, 0.0, tip);
 | 
			
		||||
	uiBut *but= ui_def_but(block, SEARCH_MENU, retval, "", x1, y1, x2, y2, arg, 0.0, maxlen, a1, a2, tip);
 | 
			
		||||
	
 | 
			
		||||
	but->icon= (BIFIconID) icon;
 | 
			
		||||
	but->flag|= UI_HAS_ICON;
 | 
			
		||||
 
 | 
			
		||||
@@ -940,7 +940,7 @@ static void icon_draw_size(float x, float y, int icon_id, float aspect, float al
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ui_id_icon_render(bContext *C, ID *id)
 | 
			
		||||
void ui_id_icon_render(bContext *C, ID *id, int preview)
 | 
			
		||||
{
 | 
			
		||||
	PreviewImage *pi = BKE_previewimg_get(id); 
 | 
			
		||||
		
 | 
			
		||||
@@ -948,13 +948,17 @@ void ui_id_icon_render(bContext *C, ID *id)
 | 
			
		||||
		if ((pi->changed[0] ||!pi->rect[0])) /* changed only ever set by dynamic icons */
 | 
			
		||||
		{
 | 
			
		||||
			/* create the preview rect if necessary */				
 | 
			
		||||
			icon_set_image(C, id, pi, 0);
 | 
			
		||||
			
 | 
			
		||||
			icon_set_image(C, id, pi, 0);		/* icon size */
 | 
			
		||||
			if (preview)
 | 
			
		||||
				icon_set_image(C, id, pi, 1);	/* preview size */
 | 
			
		||||
			
 | 
			
		||||
			pi->changed[0] = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ui_id_icon_get(bContext *C, ID *id)
 | 
			
		||||
int ui_id_icon_get(bContext *C, ID *id, int preview)
 | 
			
		||||
{
 | 
			
		||||
	int iconid= 0;
 | 
			
		||||
	
 | 
			
		||||
@@ -968,7 +972,7 @@ int ui_id_icon_get(bContext *C, ID *id)
 | 
			
		||||
		case ID_LA: /* fall through */
 | 
			
		||||
			iconid= BKE_icon_getid(id);
 | 
			
		||||
			/* checks if not exists, or changed */
 | 
			
		||||
			ui_id_icon_render(C, id);
 | 
			
		||||
			ui_id_icon_render(C, id, preview);
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
@@ -1004,8 +1008,18 @@ void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha)
 | 
			
		||||
	icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, 0, size, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UI_icon_draw_preview(float x, float y, int icon_id, int nocreate)
 | 
			
		||||
void UI_icon_draw_preview(float x, float y, int icon_id)
 | 
			
		||||
{
 | 
			
		||||
	icon_draw_mipmap(x, y, icon_id, 1.0f, 1.0f, PREVIEW_MIPMAP_LARGE, nocreate);
 | 
			
		||||
	icon_draw_mipmap(x, y, icon_id, 1.0f, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
 | 
			
		||||
{
 | 
			
		||||
	icon_draw_mipmap(x, y, icon_id, aspect, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size)
 | 
			
		||||
{
 | 
			
		||||
	icon_draw_size(x, y, icon_id, aspect, 1.0f, NULL, PREVIEW_MIPMAP_LARGE, size, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -450,13 +450,14 @@ struct ThemeUI;
 | 
			
		||||
void ui_widget_color_init(struct ThemeUI *tui);
 | 
			
		||||
 | 
			
		||||
void ui_draw_menu_item(struct uiFontStyle *fstyle, rcti *rect, char *name, int iconid, int state);
 | 
			
		||||
void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, char *name, int iconid, int state);
 | 
			
		||||
 | 
			
		||||
/* interface_style.c */
 | 
			
		||||
void uiStyleInit(void);
 | 
			
		||||
 | 
			
		||||
/* interface_icons.c */
 | 
			
		||||
void ui_id_icon_render(struct bContext *C, struct ID *id);
 | 
			
		||||
int ui_id_icon_get(struct bContext *C, struct ID *id);
 | 
			
		||||
void ui_id_icon_render(struct bContext *C, struct ID *id, int preview);
 | 
			
		||||
int ui_id_icon_get(struct bContext *C, struct ID *id, int preview);
 | 
			
		||||
 | 
			
		||||
/* resources.c */
 | 
			
		||||
void init_userdef_do_versions(void);
 | 
			
		||||
 
 | 
			
		||||
@@ -1115,7 +1115,7 @@ static void rna_search_cb(const struct bContext *C, void *arg_but, char *str, ui
 | 
			
		||||
				continue;
 | 
			
		||||
		
 | 
			
		||||
		if(RNA_struct_is_ID(itemptr.type))
 | 
			
		||||
			iconid= ui_id_icon_get((bContext*)C, itemptr.data);
 | 
			
		||||
			iconid= ui_id_icon_get((bContext*)C, itemptr.data, 0);
 | 
			
		||||
		
 | 
			
		||||
		name= RNA_struct_name_get_alloc(&itemptr, NULL, 0);
 | 
			
		||||
		
 | 
			
		||||
 
 | 
			
		||||
@@ -547,6 +547,8 @@ typedef struct uiSearchboxData {
 | 
			
		||||
	uiSearchItems items;
 | 
			
		||||
	int active;		/* index in items array */
 | 
			
		||||
	int noback;		/* when menu opened with enough space for this */
 | 
			
		||||
	int preview;	/* draw thumbnail previews, rather than list */
 | 
			
		||||
	int prv_rows, prv_cols;
 | 
			
		||||
} uiSearchboxData;
 | 
			
		||||
 | 
			
		||||
#define SEARCH_ITEMS	10
 | 
			
		||||
@@ -628,6 +630,25 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
 | 
			
		||||
 | 
			
		||||
static void ui_searchbox_butrect(rcti *rect, uiSearchboxData *data, int itemnr)
 | 
			
		||||
{
 | 
			
		||||
	/* thumbnail preview */
 | 
			
		||||
	if (data->preview) {
 | 
			
		||||
		int buth = (data->bbox.ymax - data->bbox.ymin - 2*MENU_TOP) / data->prv_rows;
 | 
			
		||||
		int butw = (data->bbox.xmax - data->bbox.xmin) / data->prv_cols;
 | 
			
		||||
		int row, col;
 | 
			
		||||
		
 | 
			
		||||
		*rect= data->bbox;
 | 
			
		||||
		
 | 
			
		||||
		col = itemnr % data->prv_cols;
 | 
			
		||||
		row = itemnr / data->prv_cols;
 | 
			
		||||
		
 | 
			
		||||
		rect->xmin += col * butw;
 | 
			
		||||
		rect->xmax = rect->xmin + butw;
 | 
			
		||||
		
 | 
			
		||||
		rect->ymax = data->bbox.ymax - (row * buth);
 | 
			
		||||
		rect->ymin = rect->ymax - buth;
 | 
			
		||||
	}
 | 
			
		||||
	/* list view */
 | 
			
		||||
	else {
 | 
			
		||||
		int buth= (data->bbox.ymax-data->bbox.ymin - 2*MENU_TOP)/SEARCH_ITEMS;
 | 
			
		||||
		
 | 
			
		||||
		*rect= data->bbox;
 | 
			
		||||
@@ -636,6 +657,7 @@ static void ui_searchbox_butrect(rcti *rect, uiSearchboxData *data, int itemnr)
 | 
			
		||||
		
 | 
			
		||||
		rect->ymax= data->bbox.ymax - MENU_TOP - itemnr*buth;
 | 
			
		||||
		rect->ymin= rect->ymax - buth;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -800,6 +822,33 @@ static void ui_searchbox_region_draw(const bContext *C, ARegion *ar)
 | 
			
		||||
		rcti rect;
 | 
			
		||||
		int a;
 | 
			
		||||
		
 | 
			
		||||
		if (data->preview) {
 | 
			
		||||
			/* draw items */
 | 
			
		||||
			for(a=0; a<data->items.totitem; a++) {
 | 
			
		||||
				ui_searchbox_butrect(&rect, data, a);
 | 
			
		||||
				
 | 
			
		||||
				/* widget itself */
 | 
			
		||||
				if (data->preview)
 | 
			
		||||
					ui_draw_preview_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
 | 
			
		||||
				else 
 | 
			
		||||
					ui_draw_menu_item(&data->fstyle, &rect, data->items.names[a], data->items.icons[a], (a+1)==data->active?UI_ACTIVE:0);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			/* indicate more */
 | 
			
		||||
			if(data->items.more) {
 | 
			
		||||
				ui_searchbox_butrect(&rect, data, data->items.maxitem-1);
 | 
			
		||||
				glEnable(GL_BLEND);
 | 
			
		||||
				UI_icon_draw(rect.xmax-18, rect.ymin-7, ICON_TRIA_DOWN);
 | 
			
		||||
				glDisable(GL_BLEND);
 | 
			
		||||
			}
 | 
			
		||||
			if(data->items.offset) {
 | 
			
		||||
				ui_searchbox_butrect(&rect, data, 0);
 | 
			
		||||
				glEnable(GL_BLEND);
 | 
			
		||||
				UI_icon_draw(rect.xmin, rect.ymax-9, ICON_TRIA_UP);
 | 
			
		||||
				glDisable(GL_BLEND);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
		} else {
 | 
			
		||||
			/* draw items */
 | 
			
		||||
			for(a=0; a<data->items.totitem; a++) {
 | 
			
		||||
				ui_searchbox_butrect(&rect, data, a);
 | 
			
		||||
@@ -822,6 +871,7 @@ static void ui_searchbox_region_draw(const bContext *C, ARegion *ar)
 | 
			
		||||
				glDisable(GL_BLEND);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ui_searchbox_region_free(ARegion *ar)
 | 
			
		||||
@@ -830,7 +880,7 @@ static void ui_searchbox_region_free(ARegion *ar)
 | 
			
		||||
	int a;
 | 
			
		||||
 | 
			
		||||
	/* free search data */
 | 
			
		||||
	for(a=0; a<SEARCH_ITEMS; a++)
 | 
			
		||||
	for(a=0; a<data->items.maxitem; a++)
 | 
			
		||||
		MEM_freeN(data->items.names[a]);
 | 
			
		||||
	MEM_freeN(data->items.names);
 | 
			
		||||
	MEM_freeN(data->items.pointers);
 | 
			
		||||
@@ -876,8 +926,13 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
 | 
			
		||||
	if(but->block->flag & UI_BLOCK_LOOP)
 | 
			
		||||
		data->noback= 1;
 | 
			
		||||
	
 | 
			
		||||
	/* compute position */
 | 
			
		||||
	if (but->a1 > 0 && but->a2 > 0) {
 | 
			
		||||
		data->preview = 1;
 | 
			
		||||
		data->prv_rows = but->a1;
 | 
			
		||||
		data->prv_cols = but->a2;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* compute position */
 | 
			
		||||
	if(but->block->flag & UI_BLOCK_LOOP) {
 | 
			
		||||
		/* this case is search menu inside other menu */
 | 
			
		||||
		/* we copy region size */
 | 
			
		||||
@@ -972,13 +1027,17 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
 | 
			
		||||
	ED_region_tag_redraw(ar);
 | 
			
		||||
	
 | 
			
		||||
	/* prepare search data */
 | 
			
		||||
	if (data->preview) {
 | 
			
		||||
		data->items.maxitem= data->prv_rows * data->prv_cols;
 | 
			
		||||
	} else {
 | 
			
		||||
		data->items.maxitem= SEARCH_ITEMS;
 | 
			
		||||
	}
 | 
			
		||||
	data->items.maxstrlen= but->hardmax;
 | 
			
		||||
	data->items.totitem= 0;
 | 
			
		||||
	data->items.names= MEM_callocN(SEARCH_ITEMS*sizeof(void *), "search names");
 | 
			
		||||
	data->items.pointers= MEM_callocN(SEARCH_ITEMS*sizeof(void *), "search pointers");
 | 
			
		||||
	data->items.icons= MEM_callocN(SEARCH_ITEMS*sizeof(int), "search icons");
 | 
			
		||||
	for(x1=0; x1<SEARCH_ITEMS; x1++)
 | 
			
		||||
	data->items.names= MEM_callocN(data->items.maxitem*sizeof(void *), "search names");
 | 
			
		||||
	data->items.pointers= MEM_callocN(data->items.maxitem*sizeof(void *), "search pointers");
 | 
			
		||||
	data->items.icons= MEM_callocN(data->items.maxitem*sizeof(int), "search icons");
 | 
			
		||||
	for(x1=0; x1<data->items.maxitem; x1++)
 | 
			
		||||
		data->items.names[x1]= MEM_callocN(but->hardmax+1, "search pointers");
 | 
			
		||||
	
 | 
			
		||||
	return ar;
 | 
			
		||||
 
 | 
			
		||||
@@ -122,6 +122,7 @@ typedef struct TemplateID {
 | 
			
		||||
	PropertyRNA *prop;
 | 
			
		||||
 | 
			
		||||
	ListBase *idlb;
 | 
			
		||||
	int prv_rows, prv_cols;
 | 
			
		||||
} TemplateID;
 | 
			
		||||
 | 
			
		||||
/* Search browse menu, assign  */
 | 
			
		||||
@@ -150,7 +151,7 @@ static void id_search_cb(const bContext *C, void *arg_template, char *str, uiSea
 | 
			
		||||
	/* ID listbase */
 | 
			
		||||
	for(id= lb->first; id; id= id->next) {
 | 
			
		||||
		if(BLI_strcasestr(id->name+2, str)) {
 | 
			
		||||
			iconid= ui_id_icon_get((bContext*)C, id);
 | 
			
		||||
			iconid= ui_id_icon_get((bContext*)C, id, 0);
 | 
			
		||||
 | 
			
		||||
			if(!uiSearchItemAdd(items, id->name+2, id, iconid))
 | 
			
		||||
				break;
 | 
			
		||||
@@ -180,11 +181,26 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
 | 
			
		||||
	block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
 | 
			
		||||
	uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
 | 
			
		||||
	
 | 
			
		||||
	/* preview thumbnails */
 | 
			
		||||
	if (template.prv_rows > 0 && template.prv_cols > 0) {
 | 
			
		||||
		int w = 96 * template.prv_cols;
 | 
			
		||||
		int h = 96 * template.prv_rows + 20;
 | 
			
		||||
		
 | 
			
		||||
		/* fake button, it holds space for search items */
 | 
			
		||||
		uiDefBut(block, LABEL, 0, "", 10, 15, w, h, NULL, 0, 0, 0, 0, NULL);
 | 
			
		||||
		
 | 
			
		||||
		but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, w, 19, template.prv_rows, template.prv_cols, "");
 | 
			
		||||
		uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
 | 
			
		||||
	}
 | 
			
		||||
	/* list view */
 | 
			
		||||
	else {
 | 
			
		||||
		/* fake button, it holds space for search items */
 | 
			
		||||
		uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
 | 
			
		||||
		
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, "");
 | 
			
		||||
		but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
 | 
			
		||||
		uiButSetSearchFunc(but, id_search_cb, &template, id_search_call_cb, idptr.data);
 | 
			
		||||
	}
 | 
			
		||||
		
 | 
			
		||||
	
 | 
			
		||||
	uiBoundsBlock(block, 6);
 | 
			
		||||
	uiBlockSetDirection(block, UI_DOWN);	
 | 
			
		||||
@@ -293,9 +309,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void template_ID(bContext *C, uiBlock *block, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop)
 | 
			
		||||
static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop)
 | 
			
		||||
{
 | 
			
		||||
	uiBut *but;
 | 
			
		||||
	uiBlock *block;
 | 
			
		||||
	PointerRNA idptr;
 | 
			
		||||
	ListBase *lb;
 | 
			
		||||
	ID *id, *idfrom;
 | 
			
		||||
@@ -305,11 +322,27 @@ static void template_ID(bContext *C, uiBlock *block, TemplateID *template, Struc
 | 
			
		||||
	idfrom= template->ptr.id.data;
 | 
			
		||||
	lb= template->idlb;
 | 
			
		||||
 | 
			
		||||
	block= uiLayoutGetBlock(layout);
 | 
			
		||||
	uiBlockBeginAlign(block);
 | 
			
		||||
 | 
			
		||||
	if(idptr.type)
 | 
			
		||||
		type= idptr.type;
 | 
			
		||||
 | 
			
		||||
	if(flag & UI_ID_PREVIEWS) {
 | 
			
		||||
 | 
			
		||||
		but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*6, UI_UNIT_Y*6, "Browse ID data");
 | 
			
		||||
		if(type) {
 | 
			
		||||
			but->icon= RNA_struct_ui_icon(type);
 | 
			
		||||
			if (id) but->icon = ui_id_icon_get(C, id, 1);
 | 
			
		||||
			uiButSetFlag(but, UI_HAS_ICON|UI_ICON_PREVIEW);
 | 
			
		||||
		}
 | 
			
		||||
		if((idfrom && idfrom->lib))
 | 
			
		||||
			uiButSetFlag(but, UI_BUT_DISABLED);
 | 
			
		||||
		
 | 
			
		||||
		
 | 
			
		||||
		uiLayoutRow(layout, 1);
 | 
			
		||||
	} else 
 | 
			
		||||
		
 | 
			
		||||
	if(flag & UI_ID_BROWSE) {
 | 
			
		||||
		but= uiDefBlockButN(block, id_search_menu, MEM_dupallocN(template), "", 0, 0, UI_UNIT_X*1.6, UI_UNIT_Y, "Browse ID data");
 | 
			
		||||
		if(type) {
 | 
			
		||||
@@ -412,10 +445,9 @@ static void template_ID(bContext *C, uiBlock *block, TemplateID *template, Struc
 | 
			
		||||
	uiBlockEndAlign(block);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
 | 
			
		||||
static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int previews, int prv_rows, int prv_cols)
 | 
			
		||||
{
 | 
			
		||||
	TemplateID *template;
 | 
			
		||||
	uiBlock *block;
 | 
			
		||||
	PropertyRNA *prop;
 | 
			
		||||
	StructRNA *type;
 | 
			
		||||
	int flag;
 | 
			
		||||
@@ -430,6 +462,8 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname
 | 
			
		||||
	template= MEM_callocN(sizeof(TemplateID), "TemplateID");
 | 
			
		||||
	template->ptr= *ptr;
 | 
			
		||||
	template->prop= prop;
 | 
			
		||||
	template->prv_rows = prv_rows;
 | 
			
		||||
	template->prv_cols = prv_cols;
 | 
			
		||||
	
 | 
			
		||||
	flag= UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE;
 | 
			
		||||
 | 
			
		||||
@@ -437,6 +471,8 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname
 | 
			
		||||
		flag |= UI_ID_ADD_NEW;
 | 
			
		||||
	if(openop)
 | 
			
		||||
		flag |= UI_ID_OPEN;
 | 
			
		||||
	if(previews)
 | 
			
		||||
		flag |= UI_ID_PREVIEWS;
 | 
			
		||||
	
 | 
			
		||||
	type= RNA_property_pointer_type(ptr, prop);
 | 
			
		||||
	template->idlb= wich_libbase(CTX_data_main(C), RNA_type_to_ID_code(type));
 | 
			
		||||
@@ -446,11 +482,21 @@ void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname
 | 
			
		||||
	 */
 | 
			
		||||
	if(template->idlb) {
 | 
			
		||||
		uiLayoutRow(layout, 1);
 | 
			
		||||
		block= uiLayoutGetBlock(layout);
 | 
			
		||||
		template_ID(C, block, template, type, flag, newop, openop, unlinkop);
 | 
			
		||||
		template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	MEM_freeN(template);
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
 | 
			
		||||
{
 | 
			
		||||
	ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, 0, 0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int rows, int cols)
 | 
			
		||||
{
 | 
			
		||||
	ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, 1, rows, cols);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/************************ ID Chooser Template ***************************/
 | 
			
		||||
@@ -1944,7 +1990,7 @@ static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon)
 | 
			
		||||
 | 
			
		||||
	/* get icon from ID */
 | 
			
		||||
	if(id) {
 | 
			
		||||
		icon= ui_id_icon_get(C, id);
 | 
			
		||||
		icon= ui_id_icon_get(C, id, 1);
 | 
			
		||||
 | 
			
		||||
		if(icon)
 | 
			
		||||
			return icon;
 | 
			
		||||
@@ -2245,7 +2291,7 @@ void uiTemplateOperatorSearch(uiLayout *layout)
 | 
			
		||||
	block= uiLayoutGetBlock(layout);
 | 
			
		||||
	uiBlockSetCurLayout(block, layout);
 | 
			
		||||
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, "");
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X*6, UI_UNIT_Y, 0, 0, "");
 | 
			
		||||
	uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -695,6 +695,27 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
 | 
			
		||||
 | 
			
		||||
/* *********************** text/icon ************************************** */
 | 
			
		||||
 | 
			
		||||
#define PREVIEW_PAD	4
 | 
			
		||||
 | 
			
		||||
static void widget_draw_preview(BIFIconID icon, float aspect, float alpha, rcti *rect)
 | 
			
		||||
{
 | 
			
		||||
	int w, h, x, y, size;
 | 
			
		||||
	
 | 
			
		||||
	/* only display previews for actual preview images .. ? */
 | 
			
		||||
	if (icon < BIFICONID_LAST)
 | 
			
		||||
		return;
 | 
			
		||||
	
 | 
			
		||||
	w = rect->xmax - rect->xmin;
 | 
			
		||||
	h = rect->ymax - rect->ymin;
 | 
			
		||||
	size = MIN2(w, h);
 | 
			
		||||
	size -= PREVIEW_PAD*2;	/* padding */
 | 
			
		||||
	
 | 
			
		||||
	x = rect->xmin + w/2 - size/2;
 | 
			
		||||
	y = rect->ymin + h/2 - size/2;
 | 
			
		||||
	
 | 
			
		||||
	UI_icon_draw_preview_aspect_size(x, y, icon, aspect, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* icons have been standardized... and this call draws in untransformed coordinates */
 | 
			
		||||
#define ICON_HEIGHT		16.0f
 | 
			
		||||
@@ -704,6 +725,11 @@ static void widget_draw_icon(uiBut *but, BIFIconID icon, float alpha, rcti *rect
 | 
			
		||||
	int xs=0, ys=0;
 | 
			
		||||
	float aspect, height;
 | 
			
		||||
	
 | 
			
		||||
	if (but->flag & UI_ICON_PREVIEW) {
 | 
			
		||||
		widget_draw_preview(icon, but->block->aspect, alpha, rect);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* this icon doesn't need draw... */
 | 
			
		||||
	if(icon==ICON_BLANK1 && (but->flag & UI_ICON_SUBMENU)==0) return;
 | 
			
		||||
	
 | 
			
		||||
@@ -2692,3 +2718,25 @@ void ui_draw_menu_item(uiFontStyle *fstyle, rcti *rect, char *name, int iconid,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ui_draw_preview_item(uiFontStyle *fstyle, rcti *rect, char *name, int iconid, int state)
 | 
			
		||||
{
 | 
			
		||||
	rcti trect = *rect;
 | 
			
		||||
	
 | 
			
		||||
	uiWidgetType *wt= widget_type(UI_WTYPE_MENU_ITEM);
 | 
			
		||||
	
 | 
			
		||||
	wt->state(wt, state);
 | 
			
		||||
	wt->draw(&wt->wcol, rect, 0, 0);
 | 
			
		||||
	
 | 
			
		||||
	widget_draw_preview(iconid, 1.f, 1.f, rect);
 | 
			
		||||
	
 | 
			
		||||
	if (state == UI_ACTIVE)
 | 
			
		||||
		glColor3ubv((unsigned char*)wt->wcol.text);
 | 
			
		||||
	else
 | 
			
		||||
		glColor3ubv((unsigned char*)wt->wcol.text_sel);
 | 
			
		||||
	
 | 
			
		||||
	trect.xmin += 0;
 | 
			
		||||
	trect.xmax = trect.xmin + BLF_width(name) + 10;
 | 
			
		||||
	trect.ymin += 10;
 | 
			
		||||
	trect.ymax = trect.ymin + BLF_height(name);
 | 
			
		||||
	uiStyleFontDraw(fstyle, &trect, name);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2890,7 +2890,7 @@ static void project_paint_begin(ProjPaintState *ps)
 | 
			
		||||
	
 | 
			
		||||
	ps->is_airbrush = (ps->brush->flag & BRUSH_AIRBRUSH) ? 1 : 0;
 | 
			
		||||
	
 | 
			
		||||
	ps->is_texbrush = (ps->brush->mtex[ps->brush->texact] && ps->brush->mtex[ps->brush->texact]->tex) ? 1 : 0;
 | 
			
		||||
	ps->is_texbrush = (ps->brush->mtex.tex) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* calculate vert screen coords
 | 
			
		||||
 
 | 
			
		||||
@@ -614,12 +614,9 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float
 | 
			
		||||
/* Return a multiplier for brush strength on a particular vertex. */
 | 
			
		||||
static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
 | 
			
		||||
{
 | 
			
		||||
	MTex *tex = NULL;
 | 
			
		||||
	MTex *tex = &br->mtex;
 | 
			
		||||
	float avg= 1;
 | 
			
		||||
 | 
			
		||||
	if(br->texact >= 0)
 | 
			
		||||
		tex = br->mtex[br->texact];
 | 
			
		||||
 | 
			
		||||
	if(!tex) {
 | 
			
		||||
		avg= 1;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -626,7 +626,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
 | 
			
		||||
			Brush *br= ptr->data;
 | 
			
		||||
 | 
			
		||||
			if(br)
 | 
			
		||||
				CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, br->mtex[(int)br->texact]);
 | 
			
		||||
				CTX_data_pointer_set(result, &br->id, &RNA_BrushTextureSlot, &br->mtex);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -335,6 +335,10 @@ static void buttons_area_listener(ScrArea *sa, wmNotifier *wmn)
 | 
			
		||||
			buttons_area_redraw(sa, BCONTEXT_DATA);
 | 
			
		||||
			sbuts->preview= 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case NC_BRUSH:
 | 
			
		||||
			buttons_area_redraw(sa, BCONTEXT_TEXTURE);
 | 
			
		||||
			sbuts->preview= 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case NC_TEXTURE:
 | 
			
		||||
			ED_area_tag_redraw(sa);
 | 
			
		||||
			sbuts->preview= 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -5029,7 +5029,7 @@ static uiBlock *operator_search_menu(bContext *C, ARegion *ar, void *arg_kmi)
 | 
			
		||||
	/* fake button, it holds space for search items */
 | 
			
		||||
	uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
 | 
			
		||||
	
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, "");
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 0, 150, 19, 0, 0, "");
 | 
			
		||||
	uiButSetSearchFunc(but, operator_search_cb, arg_kmi, operator_call_cb, ot);
 | 
			
		||||
	
 | 
			
		||||
	uiBoundsBlock(block, 6);
 | 
			
		||||
 
 | 
			
		||||
@@ -239,7 +239,7 @@ static uiBlock *tool_search_menu(bContext *C, ARegion *ar, void *arg_listbase)
 | 
			
		||||
	/* fake button, it holds space for search items */
 | 
			
		||||
	uiDefBut(block, LABEL, 0, "", 10, 15, 150, uiSearchBoxhHeight(), NULL, 0, 0, 0, 0, NULL);
 | 
			
		||||
	
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, OP_MAX_TYPENAME, 10, 0, 150, 19, "");
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, OP_MAX_TYPENAME, 10, 0, 150, 19, 0, 0, "");
 | 
			
		||||
	uiButSetSearchFunc(but, operator_search_cb, arg_listbase, operator_call_cb, NULL);
 | 
			
		||||
	
 | 
			
		||||
	uiBoundsBlock(block, 6);
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,7 @@
 | 
			
		||||
#define DNA_BRUSH_TYPES_H
 | 
			
		||||
 | 
			
		||||
#include "DNA_ID.h"
 | 
			
		||||
#include "DNA_texture_types.h"
 | 
			
		||||
 | 
			
		||||
#ifndef MAX_MTEX
 | 
			
		||||
#define MAX_MTEX	18
 | 
			
		||||
@@ -50,9 +51,8 @@ typedef struct Brush {
 | 
			
		||||
	ID id;
 | 
			
		||||
 | 
			
		||||
	struct BrushClone clone;
 | 
			
		||||
 | 
			
		||||
	struct CurveMapping *curve;	/* falloff curve */
 | 
			
		||||
	struct MTex *mtex[18];		/* MAX_MTEX */
 | 
			
		||||
	struct MTex mtex;
 | 
			
		||||
	
 | 
			
		||||
	short flag, blend;			/* general purpose flag, blend mode */
 | 
			
		||||
	int size;					/* brush diameter */
 | 
			
		||||
@@ -65,10 +65,8 @@ typedef struct Brush {
 | 
			
		||||
	float rgb[3];				/* color */
 | 
			
		||||
	float alpha;				/* opacity */
 | 
			
		||||
 | 
			
		||||
	short texact;				/* active texture */
 | 
			
		||||
	char sculpt_tool;			/* active tool */
 | 
			
		||||
	
 | 
			
		||||
	char pad[1];
 | 
			
		||||
	char pad2[3];
 | 
			
		||||
} Brush;
 | 
			
		||||
 | 
			
		||||
/* Brush.flag */
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@
 | 
			
		||||
#include "DNA_texture_types.h"
 | 
			
		||||
 | 
			
		||||
#include "IMB_imbuf.h"
 | 
			
		||||
#include "WM_types.h"
 | 
			
		||||
 | 
			
		||||
EnumPropertyItem brush_sculpt_tool_items[] = {
 | 
			
		||||
	{SCULPT_TOOL_DRAW, "DRAW", 0, "Draw", ""},
 | 
			
		||||
@@ -52,29 +53,6 @@ EnumPropertyItem brush_sculpt_tool_items[] = {
 | 
			
		||||
#include "BKE_texture.h"
 | 
			
		||||
 | 
			
		||||
#include "WM_api.h"
 | 
			
		||||
#include "WM_types.h"
 | 
			
		||||
 | 
			
		||||
static void rna_Brush_mtex_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 | 
			
		||||
{
 | 
			
		||||
	Brush *brush= (Brush*)ptr->data;
 | 
			
		||||
	rna_iterator_array_begin(iter, (void*)brush->mtex, sizeof(MTex*), MAX_MTEX, 0, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PointerRNA rna_Brush_active_texture_get(PointerRNA *ptr)
 | 
			
		||||
{
 | 
			
		||||
	Brush *br= (Brush*)ptr->data;
 | 
			
		||||
	Tex *tex;
 | 
			
		||||
 | 
			
		||||
	tex= give_current_brush_texture(br);
 | 
			
		||||
	return rna_pointer_inherit_refine(ptr, &RNA_Texture, tex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rna_Brush_active_texture_set(PointerRNA *ptr, PointerRNA value)
 | 
			
		||||
{
 | 
			
		||||
	Brush *br= (Brush*)ptr->data;
 | 
			
		||||
 | 
			
		||||
	set_current_brush_texture(br, value.data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rna_Brush_update(Main *bmain, Scene *scene, PointerRNA *ptr)
 | 
			
		||||
{
 | 
			
		||||
@@ -291,8 +269,17 @@ static void rna_def_brush(BlenderRNA *brna)
 | 
			
		||||
	RNA_def_property_update(prop, 0, "rna_Brush_update");
 | 
			
		||||
 | 
			
		||||
	/* texture */
 | 
			
		||||
	rna_def_mtex_common(srna, "rna_Brush_mtex_begin", "rna_Brush_active_texture_get",
 | 
			
		||||
		"rna_Brush_active_texture_set", "BrushTextureSlot", "rna_Brush_update");
 | 
			
		||||
	prop= RNA_def_property(srna, "texture_slot", PROP_POINTER, PROP_NONE);
 | 
			
		||||
	RNA_def_property_struct_type(prop, "BrushTextureSlot");
 | 
			
		||||
	RNA_def_property_pointer_sdna(prop, NULL, "mtex");
 | 
			
		||||
	RNA_def_property_clear_flag(prop, PROP_EDITABLE);
 | 
			
		||||
	RNA_def_property_ui_text(prop, "Texture Slot", "");
 | 
			
		||||
	
 | 
			
		||||
	prop= RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE);
 | 
			
		||||
	RNA_def_property_pointer_sdna(prop, NULL, "mtex.tex");
 | 
			
		||||
	RNA_def_property_flag(prop, PROP_EDITABLE);
 | 
			
		||||
	RNA_def_property_ui_text(prop, "Texture", "");
 | 
			
		||||
	RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_update");
 | 
			
		||||
 | 
			
		||||
	/* clone tool */
 | 
			
		||||
	prop= RNA_def_property(srna, "clone_image", PROP_POINTER, PROP_NONE);
 | 
			
		||||
 
 | 
			
		||||
@@ -269,6 +269,15 @@ void RNA_api_ui_layout(StructRNA *srna)
 | 
			
		||||
	RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a file for creating a new ID block.");
 | 
			
		||||
	RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
 | 
			
		||||
	
 | 
			
		||||
	func= RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview");
 | 
			
		||||
	RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 | 
			
		||||
	api_ui_item_rna_common(func);
 | 
			
		||||
	RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block.");
 | 
			
		||||
	RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a file for creating a new ID block.");
 | 
			
		||||
	RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
 | 
			
		||||
	RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
 | 
			
		||||
	RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
 | 
			
		||||
	
 | 
			
		||||
	func= RNA_def_function(srna, "template_any_ID", "uiTemplateAnyID");
 | 
			
		||||
	RNA_def_function_flag(func, FUNC_USE_CONTEXT);
 | 
			
		||||
	parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property.");
 | 
			
		||||
 
 | 
			
		||||
@@ -1037,7 +1037,7 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *arg_op)
 | 
			
		||||
	block= uiBeginBlock(C, ar, "_popup", UI_EMBOSS);
 | 
			
		||||
	uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_RET_1|UI_BLOCK_MOVEMOUSE_QUIT);
 | 
			
		||||
	
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 10, 180, 19, "");
 | 
			
		||||
	but= uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, 256, 10, 10, 180, 19, 0, 0, "");
 | 
			
		||||
	uiButSetSearchFunc(but, operator_search_cb, NULL, operator_call_cb, NULL);
 | 
			
		||||
	
 | 
			
		||||
	/* fake button, it holds space for search items */
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user