Initially add widget files and get them compiling

Another temp_ branch :S This time for preparing custom manipulators core code for merge.
This commit is contained in:
Julian Eisel
2016-09-08 21:32:44 +02:00
parent 45f833c21d
commit ae55eeb2ce
34 changed files with 5853 additions and 0 deletions

View File

@@ -87,6 +87,7 @@ set(SRC_DNA_INC
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_vfont_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view2d_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_view3d_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_widget_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_windowmanager_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_world_types.h
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_movieclip_types.h

View File

@@ -304,6 +304,7 @@ void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
void ortho_v3_v3(float out[3], const float v[3]);
void ortho_v2_v2(float out[2], const float v[2]);
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
void rotate_v2_v2fl(float r[2], const float p[2], const float angle);
void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
void rotate_normalized_v3_v3v3fl(float out[3], const float p[3], const float axis[3], const float angle);

View File

@@ -771,6 +771,20 @@ void ortho_v2_v2(float out[2], const float v[2])
out[1] = v[0];
}
/**
* Rotate a point \a p by \a angle around origin (0, 0)
*/
void rotate_v2_v2fl(float r[2], const float p[2], const float angle)
{
const float co = cosf(angle);
const float si = sinf(angle);
BLI_assert(r != p);
r[0] = co * p[0] - si * p[1];
r[1] = si * p[0] + co * p[1];
}
/**
* Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
* http://local.wasp.uwa.edu.au/~pbourke/geometry/

View File

@@ -1656,6 +1656,8 @@ void init_userdef_do_versions(void)
U.tw_size = 25; /* percentage of window size */
U.tw_handlesize = 16; /* percentage of widget radius */
}
if (U.widget_scale == 0)
U.widget_scale = 75;
if (U.pad_rot_angle == 0.0f)
U.pad_rot_angle = 15.0f;

View File

@@ -264,6 +264,7 @@ typedef struct ARegion {
ListBase ui_lists; /* uiList */
ListBase ui_previews; /* uiPreview */
ListBase handlers; /* wmEventHandler */
ListBase widgetmaps; /* widgetmaps */
ListBase panels_category; /* Panel categories runtime */
struct wmTimer *regiontimer; /* blend in/out */

View File

@@ -46,6 +46,7 @@
#include "DNA_node_types.h" /* for bNodeInstanceKey */
/* Hum ... Not really nice... but needed for spacebuts. */
#include "DNA_view2d_types.h"
#include "DNA_widget_types.h"
struct ID;
struct Text;

View File

@@ -490,6 +490,8 @@ typedef struct UserDef {
short tb_leftmouse, tb_rightmouse;
struct SolidLight light[3];
short tw_hotspot, tw_flag, tw_handlesize, tw_size;
short widget_flag, widget_scale;
int pad3;
short textimeout, texcollectrate;
short wmdrawmethod; /* removed wmpad */
short dragthreshold;

View File

@@ -368,6 +368,8 @@ enum {
#define V3D_USE_MANIPULATOR 1
#define V3D_DRAW_MANIPULATOR 2
/* #define V3D_CALC_MANIPULATOR 4 */ /*UNUSED*/
#define V3D_3D_WIDGETS (1 << 2)
#define V3D_SHADED_WIDGETS (1 << 3)
/* BGPic->flag */
/* may want to use 1 for select ? */

View File

@@ -0,0 +1,57 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file DNA_widget_types.h
* \ingroup DNA
*/
#ifndef __DNA_WIDGET_TYPES_H__
#define __DNA_WIDGET_TYPES_H__
typedef enum WidgetType {
WT_TRANSLATE = 0,
WT_ROTATE = 1,
WT_SCALE = 2,
WT_CUSTOM = 3,
} WidgetType;
typedef struct wmWidgetGroup {
struct wmWidgetGroup *next, *prev;
struct wmWidgetGroupType *type;
ListBase widgets;
void *py_instance; /* python stores the class instance here */
struct ReportList *reports; /* errors and warnings storage */
void *customdata;
void (*customdata_free)(void *); /* for freeing customdata from above */
int flag;
int pad;
} wmWidgetGroup;
#endif /* __DNA_WIDGET_TYPES_H__ */

View File

@@ -118,6 +118,7 @@ static const char *includefiles[] = {
"DNA_cloth_types.h",
"DNA_gpencil_types.h",
"DNA_windowmanager_types.h",
"DNA_widget_types.h",
"DNA_anim_types.h",
"DNA_boid_types.h",
"DNA_smoke_types.h",
@@ -1330,6 +1331,7 @@ int main(int argc, char **argv)
#include "DNA_cloth_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_widget_types.h"
#include "DNA_anim_types.h"
#include "DNA_boid_types.h"
#include "DNA_smoke_types.h"

View File

@@ -25,6 +25,8 @@
set(INC
.
widgets
widgets/intern
../blenfont
../blenkernel
../blenlib
@@ -68,6 +70,18 @@ set(SRC
intern/wm_subwindow.c
intern/wm_window.c
intern/wm_stereo.c
widgets/intern/wm_widget.c
widgets/intern/wm_widgetgroup.c
widgets/intern/wm_widgetmap.c
widgets/intern/widget_library/arrow_widget.c
widgets/intern/widget_library/arrow2d_widget.c
widgets/intern/widget_library/cage_widget.c
widgets/intern/widget_library/dial_widget.c
widgets/intern/widget_library/primitive_widget.c
widgets/intern/widget_library/geom_arrow_widget.c
widgets/intern/widget_library/geom_cube_widget
widgets/intern/widget_library/geom_dial_widget.c
widgets/intern/widget_library/widget_library_utils.c
WM_api.h
WM_keymap.h
@@ -80,6 +94,13 @@ set(SRC
wm_files.h
wm_subwindow.h
wm_window.h
widgets/WM_widget_api.h
widgets/WM_widget_types.h
widgets/WM_widget_library.h
widgets/wm_widget_wmapi.h
widgets/intern/wm_widget_intern.h
widgets/intern/widget_library/widget_geometry.h
widgets/intern/widget_library/widget_library_intern.h
)
if(WITH_AUDASPACE)

View File

@@ -42,6 +42,10 @@
#include "WM_keymap.h"
#include "BLI_compiler_attrs.h"
/* Include external widget API's */
#include "widgets/WM_widget_api.h"
#include "widgets/WM_widget_library.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -70,6 +74,8 @@ struct wmNDOFMotionData;
#endif
typedef struct wmJob wmJob;
typedef struct wmWidget wmWidget;
typedef struct wmWidgetMapType wmWidgetMapType;
/* general API */
void WM_init_state_size_set (int stax, int stay, int sizx, int sizy);

View File

@@ -119,6 +119,7 @@ struct ImBuf;
/* exported types for WM */
#include "wm_cursors.h"
#include "wm_event_types.h"
#include "widgets/WM_widget_types.h"
/* ************** wmOperatorType ************************ */
@@ -566,6 +567,9 @@ typedef struct wmOperatorType {
/* pointer to modal keymap, do not free! */
struct wmKeyMap *modalkeymap;
/* widget group that is accessible while operator runs */
wmWidgetGroupType *wgrouptype;
/* python needs the operator type as well */
int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT;

View File

@@ -0,0 +1,118 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/WM_widget_api.h
* \ingroup wm
*
* \name Widget API
* \brief API for external use of wmWidget types.
*
* Only included in WM_api.h
*/
#ifndef __WM_WIDGET_API_H__
#define __WM_WIDGET_API_H__
struct ARegion;
struct Main;
struct wmEventHandler;
struct wmKeyConfig;
struct wmKeyMap;
struct wmOperator;
struct wmWidgetGroup;
struct wmWidgetGroupType;
struct wmWidgetMap;
struct wmWidgetMapType;
struct wmWidgetMapType_Params;
/* -------------------------------------------------------------------- */
/* wmWidget */
struct wmWidget *WM_widget_new(
void (*draw)(const struct bContext *, struct wmWidget *),
void (*render_3d_intersection)(const struct bContext *, struct wmWidget *, int),
int (*intersect)(struct bContext *, const struct wmEvent *, struct wmWidget *),
int (*handler)(struct bContext *, const struct wmEvent *, struct wmWidget *, const int));
void WM_widget_delete(ListBase *widgetlist, struct wmWidgetMap *wmap, struct wmWidget *widget, struct bContext *C);
void WM_widget_set_property(struct wmWidget *, int slot, struct PointerRNA *ptr, const char *propname);
struct PointerRNA *WM_widget_set_operator(struct wmWidget *, const char *opname);
void WM_widget_set_func_select(
struct wmWidget *widget,
void (*select)(struct bContext *, struct wmWidget *, const int action)); /* wmWidgetSelectFunc */
void WM_widget_set_origin(struct wmWidget *widget, const float origin[3]);
void WM_widget_set_offset(struct wmWidget *widget, const float offset[3]);
void WM_widget_set_flag(struct wmWidget *widget, const int flag, const bool enable);
void WM_widget_set_scale(struct wmWidget *widget, float scale);
void WM_widget_set_line_width(struct wmWidget *widget, const float line_width);
void WM_widget_set_colors(struct wmWidget *widget, const float col[4], const float col_hi[4]);
/* -------------------------------------------------------------------- */
/* wmWidgetGroup */
struct wmWidgetGroupType *WM_widgetgrouptype_append(
struct wmWidgetMapType *wmaptype,
void (*wgrouptype_func)(struct wmWidgetGroupType *));
struct wmWidgetGroupType *WM_widgetgrouptype_append_runtime(
const struct Main *main, struct wmWidgetMapType *wmaptype,
void (*wgrouptype_func)(struct wmWidgetGroupType *));
void WM_widgetgrouptype_init_runtime(
const struct Main *bmain, struct wmWidgetMapType *wmaptype,
struct wmWidgetGroupType *wgrouptype);
void WM_widgetgrouptype_unregister(struct bContext *C, struct Main *bmain, struct wmWidgetGroupType *wgroup);
struct wmKeyMap *WM_widgetgroup_keymap_common(
const struct wmWidgetGroupType *wgrouptype, struct wmKeyConfig *config);
struct wmKeyMap *WM_widgetgroup_keymap_common_sel(
const struct wmWidgetGroupType *wgrouptype, struct wmKeyConfig *config);
/* -------------------------------------------------------------------- */
/* wmWidgetMap */
struct wmWidgetMapType *WM_widgetmaptype_find(const struct wmWidgetMapType_Params *wmap_params);
struct wmWidgetMapType *WM_widgetmaptype_ensure(const struct wmWidgetMapType_Params *wmap_params);
struct wmWidgetMap *WM_widgetmap_from_type(const struct wmWidgetMapType_Params *wmap_params);
struct wmWidgetMap *WM_widgetmap_find(const struct ARegion *ar, const struct wmWidgetMapType_Params *wmap_params);
void WM_widgetmap_delete(struct wmWidgetMap *wmap);
void WM_widgetmaptypes_free(void);
void WM_widgetmap_tag_refresh(struct wmWidgetMap *wmap);
void WM_widgetmap_widgets_update(const struct bContext *C, struct wmWidgetMap *wmap);
void WM_widgetmap_widgets_draw(
const struct bContext *C, const struct wmWidgetMap *wmap,
const bool in_scene, const bool free_drawwidgets);
void WM_widgetmaps_add_handlers(struct ARegion *ar);
bool WM_widgetmap_select_all(struct bContext *C, struct wmWidgetMap *wmap, const int action);
bool WM_widgetmap_cursor_set(const struct wmWidgetMap *wmap, struct wmWindow *win);
#endif /* __WM_WIDGET_API_H__ */

View File

@@ -0,0 +1,126 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/WM_widget_library.h
* \ingroup wm
*
* \name Generic Widget Library
*
* Only included in WM_api.h and lower level files.
*/
#ifndef __WM_WIDGET_LIBRARY_H__
#define __WM_WIDGET_LIBRARY_H__
struct wmWidgetGroup;
/* -------------------------------------------------------------------- */
/* 3D Arrow Widget */
enum {
WIDGET_ARROW_STYLE_NORMAL = 1,
WIDGET_ARROW_STYLE_NO_AXIS = (1 << 1),
WIDGET_ARROW_STYLE_CROSS = (1 << 2),
WIDGET_ARROW_STYLE_INVERTED = (1 << 3), /* inverted offset during interaction - if set it also sets constrained below */
WIDGET_ARROW_STYLE_CONSTRAINED = (1 << 4), /* clamp arrow interaction to property width */
WIDGET_ARROW_STYLE_BOX = (1 << 5), /* use a box for the arrowhead */
WIDGET_ARROW_STYLE_CONE = (1 << 6),
};
/* slots for properties */
enum {
ARROW_SLOT_OFFSET_WORLD_SPACE = 0
};
struct wmWidget *WIDGET_arrow_new(struct wmWidgetGroup *wgroup, const char *name, const int style);
void WIDGET_arrow_set_direction(struct wmWidget *widget, const float direction[3]);
void WIDGET_arrow_set_up_vector(struct wmWidget *widget, const float direction[3]);
void WIDGET_arrow_set_line_len(struct wmWidget *widget, const float len);
void WIDGET_arrow_set_ui_range(struct wmWidget *widget, const float min, const float max);
void WIDGET_arrow_set_range_fac(struct wmWidget *widget, const float range_fac);
void WIDGET_arrow_cone_set_aspect(struct wmWidget *widget, const float aspect[2]);
/* -------------------------------------------------------------------- */
/* 2D Arrow Widget */
struct wmWidget *WIDGET_arrow2d_new(struct wmWidgetGroup *wgroup, const char *name);
void WIDGET_arrow2d_set_angle(struct wmWidget *widget, const float rot_fac);
void WIDGET_arrow2d_set_line_len(struct wmWidget *widget, const float len);
/* -------------------------------------------------------------------- */
/* Cage Widget */
enum {
WIDGET_RECT_TRANSFORM_STYLE_TRANSLATE = 1, /* widget translates */
WIDGET_RECT_TRANSFORM_STYLE_ROTATE = (1 << 1), /* widget rotates */
WIDGET_RECT_TRANSFORM_STYLE_SCALE = (1 << 2), /* widget scales */
WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM = (1 << 3), /* widget scales uniformly */
};
enum {
RECT_TRANSFORM_SLOT_OFFSET = 0,
RECT_TRANSFORM_SLOT_SCALE = 1
};
struct wmWidget *WIDGET_rect_transform_new(struct wmWidgetGroup *wgroup, const char *name, const int style);
void WIDGET_rect_transform_set_dimensions(struct wmWidget *widget, const float width, const float height);
/* -------------------------------------------------------------------- */
/* Dial Widget */
enum {
WIDGET_DIAL_STYLE_RING = 0,
WIDGET_DIAL_STYLE_RING_CLIPPED = 1,
WIDGET_DIAL_STYLE_RING_FILLED = 2,
};
struct wmWidget *WIDGET_dial_new(struct wmWidgetGroup *wgroup, const char *name, const int style);
void WIDGET_dial_set_up_vector(struct wmWidget *widget, const float direction[3]);
/* -------------------------------------------------------------------- */
/* Facemap Widget */
struct wmWidget *WIDGET_facemap_new(
struct wmWidgetGroup *wgroup, const char *name, const int style,
struct Object *ob, const int facemap);
struct bFaceMap *WIDGET_facemap_get_fmap(struct wmWidget *widget);
/* -------------------------------------------------------------------- */
/* Primitive Widget */
enum {
WIDGET_PRIMITIVE_STYLE_PLANE = 0,
};
struct wmWidget *WIDGET_primitive_new(struct wmWidgetGroup *wgroup, const char *name, const int style);
void WIDGET_primitive_set_direction(struct wmWidget *widget, const float direction[3]);
void WIDGET_primitive_set_up_vector(struct wmWidget *widget, const float direction[3]);
#endif /* __WM_WIDGET_LIBRARY_H__ */

View File

@@ -0,0 +1,166 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/WM_widget_types.h
* \ingroup wm
*
* \name Widget Types
* \brief Widget defines for external use.
*
* Only included in WM_types.h and lower level files.
*/
#ifndef __WM_WIDGET_TYPES_H__
#define __WM_WIDGET_TYPES_H__
#include "BLI_compiler_attrs.h"
struct wmWidgetGroupType;
struct wmWidgetGroup;
struct wmKeyConfig;
typedef int (*wmWidgetGroupPollFunc)(const struct bContext *, struct wmWidgetGroupType *) ATTR_WARN_UNUSED_RESULT; /* TODO use bool */
typedef void (*wmWidgetGroupInitFunc)(const struct bContext *, struct wmWidgetGroup *);
typedef void (*wmWidgetGroupRefreshFunc)(const struct bContext *, struct wmWidgetGroup *);
typedef void (*wmWidgetGroupDrawPrepareFunc)(const struct bContext *, struct wmWidgetGroup *);
/* -------------------------------------------------------------------- */
/* factory class for a widgetgroup type, gets called every time a new area is spawned */
typedef struct wmWidgetGroupType {
struct wmWidgetGroupType *next, *prev;
char idname[64]; /* MAX_NAME */
const char *name; /* widget group name - displayed in UI (keymap editor) */
/* poll if widgetmap should be active */
wmWidgetGroupPollFunc poll;
/* initially create widgets, set permanent data stuff you only need to do once */
wmWidgetGroupInitFunc init;
/* refresh data, only called if recreate flag is set (WM_widgetmap_tag_refresh) */
wmWidgetGroupRefreshFunc refresh;
/* refresh data for drawing, called before each redraw */
wmWidgetGroupDrawPrepareFunc draw_prepare;
/* keymap init callback for this widgetgroup */
struct wmKeyMap *(*keymap_init)(const struct wmWidgetGroupType *, struct wmKeyConfig *);
/* keymap created with callback from above */
struct wmKeyMap *keymap;
/* rna for properties */
struct StructRNA *srna;
/* RNA integration */
ExtensionRNA ext;
/* widgetTypeflags (includes copy of wmWidgetMapType.flag - used for comparisons) */
int flag;
/* if type is spawned from operator this is set here */
void *op;
/* same as widgetmaps, so registering/unregistering goes to the correct region */
short spaceid, regionid;
char mapidname[64];
} wmWidgetGroupType;
typedef struct wmWidgetMap {
struct wmWidgetMap *next, *prev;
struct wmWidgetMapType *type;
ListBase widgetgroups;
char update_flag; /* private, update tagging */
/**
* \brief Widget map runtime context
*
* Contains information about this widget map. Currently
* highlighted widget, currently selected widgets, ...
*/
struct {
/* we redraw the widgetmap when this changes */
struct wmWidget *highlighted_widget;
/* user has clicked this widget and it gets all input */
struct wmWidget *active_widget;
/* array for all selected widgets
* TODO check on using BLI_array */
struct wmWidget **selected_widgets;
int tot_selected;
/* set while widget is highlighted/active */
struct wmWidgetGroup *activegroup;
} wmap_context;
} wmWidgetMap;
struct wmWidgetMapType_Params {
const char *idname;
const int spaceid;
const int regionid;
const int flag;
};
/**
* Simple utility wrapper for storing a single widget as wmWidgetGroup.customdata (which gets freed).
*/
typedef struct wmWidgetWrapper {
struct wmWidget *widget;
} wmWidgetWrapper;
/* -------------------------------------------------------------------- */
/* wmWidget->flag */
enum eWidgetFlag {
/* states */
WM_WIDGET_HIGHLIGHT = (1 << 0),
WM_WIDGET_ACTIVE = (1 << 1),
WM_WIDGET_SELECTED = (1 << 2),
/* settings */
WM_WIDGET_DRAW_HOVER = (1 << 3),
WM_WIDGET_DRAW_ACTIVE = (1 << 4), /* draw while dragging */
WM_WIDGET_DRAW_VALUE = (1 << 5), /* draw a indicator for the current value while dragging */
WM_WIDGET_SCALE_3D = (1 << 6),
WM_WIDGET_SCENE_DEPTH = (1 << 7), /* widget is depth culled with scene objects*/
WM_WIDGET_HIDDEN = (1 << 8),
WM_WIDGET_SELECTABLE = (1 << 9),
};
/* wmWidgetMapType->flag */
enum eWidgetMapTypeFlag {
/**
* Check if widgetmap does 3D drawing
* (uses a different kind of interaction),
* - 3d: use glSelect buffer.
* - 2d: use simple cursor position intersection test. */
WM_WIDGETMAPTYPE_3D = (1 << 0),
};
#endif /* __WM_WIDGET_TYPES_H__ */

View File

@@ -0,0 +1,222 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/arrow2d_widget.c
* \ingroup wm
*
* \name 2D Arrow Widget
*
* 2D Widget
*
* \brief Simple arrow widget which is dragged into a certain direction.
*/
#include "BIF_gl.h"
#include "BKE_context.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "DNA_widget_types.h"
#include "DNA_windowmanager_types.h"
#include "ED_screen.h"
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
#include "WM_types.h"
/* own includes */
#include "WM_widget_types.h"
#include "wm_widget_wmapi.h"
#include "WM_widget_library.h"
#include "wm_widget_intern.h"
#include "widget_library_intern.h"
typedef struct ArrowWidget2D {
wmWidget widget;
float angle;
float line_len;
} ArrowWidget2D;
static void arrow2d_draw_geom(ArrowWidget2D *arrow, const float origin[2])
{
const float size = 0.11f;
const float size_h = size / 2.0f;
const float len = arrow->line_len;
const float draw_line_ofs = (arrow->widget.line_width * 0.5f) / arrow->widget.scale;
glPushMatrix();
glTranslate2fv(origin);
glScalef(arrow->widget.scale, arrow->widget.scale, 0.0f);
glRotatef(RAD2DEGF(arrow->angle), 0.0f, 0.0f, 1.0f);
/* local offset */
glTranslatef(arrow->widget.offset[0] + draw_line_ofs, arrow->widget.offset[1], 0.0f);
/* TODO get rid of immediate mode */
glBegin(GL_LINES);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, len);
glEnd();
glBegin(GL_TRIANGLES);
glVertex2f(size_h, len);
glVertex2f(-size_h, len);
glVertex2f(0.0f, len + size * 1.7f);
glEnd();
glPopMatrix();
}
static void widget_arrow2d_draw(const bContext *UNUSED(C), wmWidget *widget)
{
ArrowWidget2D *arrow = (ArrowWidget2D *)widget;
const float *col = widget_color_get(widget, widget->flag & WM_WIDGET_HIGHLIGHT);
glColor4fv(col);
glLineWidth(widget->line_width);
glEnable(GL_BLEND);
arrow2d_draw_geom(arrow, widget->origin);
glDisable(GL_BLEND);
if (arrow->widget.interaction_data) {
WidgetInteraction *inter = arrow->widget.interaction_data;
glColor4f(0.5f, 0.5f, 0.5f, 0.5f);
glEnable(GL_BLEND);
arrow2d_draw_geom(arrow, inter->init_origin);
glDisable(GL_BLEND);
}
}
static int widget_arrow2d_invoke(bContext *UNUSED(C), const wmEvent *UNUSED(event), wmWidget *widget)
{
WidgetInteraction *inter = MEM_callocN(sizeof(WidgetInteraction), __func__);
copy_v2_v2(inter->init_origin, widget->origin);
widget->interaction_data = inter;
return OPERATOR_RUNNING_MODAL;
}
static int widget_arrow2d_intersect(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget)
{
ArrowWidget2D *arrow = (ArrowWidget2D *)widget;
const float mval[2] = {event->mval[0], event->mval[1]};
const float line_len = arrow->line_len * widget->scale;
float mval_local[2];
copy_v2_v2(mval_local, mval);
sub_v2_v2(mval_local, widget->origin);
float line[2][2];
line[0][0] = line[0][1] = line[1][0] = 0.0f;
line[1][1] = line_len;
/* rotate only if needed */
if (arrow->angle != 0.0f) {
float rot_point[2];
copy_v2_v2(rot_point, line[1]);
rotate_v2_v2fl(line[1], rot_point, arrow->angle);
}
/* arrow line intersection check */
float isect_1[2], isect_2[2];
const int isect = isect_line_sphere_v2(
line[0], line[1], mval_local, WIDGET_HOTSPOT + widget->line_width * 0.5f,
isect_1, isect_2);
if (isect > 0) {
float line_ext[2][2]; /* extended line for segment check including hotspot */
copy_v2_v2(line_ext[0], line[0]);
line_ext[1][0] = line[1][0] + WIDGET_HOTSPOT * ((line[1][0] - line[0][0]) / line_len);
line_ext[1][1] = line[1][1] + WIDGET_HOTSPOT * ((line[1][1] - line[0][1]) / line_len);
const float lambda_1 = line_point_factor_v2(isect_1, line_ext[0], line_ext[1]);
if (isect == 1) {
return IN_RANGE_INCL(lambda_1, 0.0f, 1.0f);
}
else {
BLI_assert(isect == 2);
const float lambda_2 = line_point_factor_v2(isect_2, line_ext[0], line_ext[1]);
return IN_RANGE_INCL(lambda_1, 0.0f, 1.0f) && IN_RANGE_INCL(lambda_2, 0.0f, 1.0f);
}
}
return 0;
}
/* -------------------------------------------------------------------- */
/** \name 2D Arrow Widget API
*
* \{ */
wmWidget *WIDGET_arrow2d_new(wmWidgetGroup *wgroup, const char *name)
{
ArrowWidget2D *arrow = MEM_callocN(sizeof(ArrowWidget2D), __func__);
arrow->widget.draw = widget_arrow2d_draw;
arrow->widget.invoke = widget_arrow2d_invoke;
// arrow->widget.bind_to_prop = widget_arrow2d_bind_to_prop;
// arrow->widget.handler = widget_arrow2d_handler;
arrow->widget.intersect = widget_arrow2d_intersect;
// arrow->widget.exit = widget_arrow2d_exit;
arrow->widget.flag |= WM_WIDGET_DRAW_ACTIVE;
arrow->line_len = 1.0f;
wm_widget_register(wgroup, &arrow->widget, name);
return (wmWidget *)arrow;
}
void WIDGET_arrow2d_set_angle(wmWidget *widget, const float angle)
{
ArrowWidget2D *arrow = (ArrowWidget2D *)widget;
arrow->angle = angle;
}
void WIDGET_arrow2d_set_line_len(wmWidget *widget, const float len)
{
ArrowWidget2D *arrow = (ArrowWidget2D *)widget;
arrow->line_len = len;
}
/** \} */ /* Arrow Widget API */
/* -------------------------------------------------------------------- */
void fix_linking_widget_arrow2d(void)
{
(void)0;
}

View File

@@ -0,0 +1,577 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2014 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/arrow_widget.c
* \ingroup wm
*
* \name Arrow Widget
*
* 3D Widget
*
* \brief Simple arrow widget which is dragged into a certain direction.
* The arrow head can have varying shapes, e.g. cone, box, etc.
*/
#include "BIF_gl.h"
#include "BKE_context.h"
#include "BLI_math.h"
#include "DNA_view3d_types.h"
#include "ED_view3d.h"
#include "ED_screen.h"
#include "GPU_select.h"
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
#include "WM_types.h"
#include "WM_api.h"
/* own includes */
#include "wm_widget_wmapi.h"
#include "wm_widget_intern.h"
#include "widget_geometry.h"
#include "widget_library_intern.h"
/* to use custom arrows exported to arrow_widget.c */
//#define WIDGET_USE_CUSTOM_ARROWS
#ifdef WIDGET_USE_CUSTOM_ARROWS
WidgetDrawInfo arrow_head_draw_info = {0};
#endif
WidgetDrawInfo cube_draw_info = {0};
/* ArrowWidget->flag */
enum {
ARROW_UP_VECTOR_SET = (1 << 0),
ARROW_CUSTOM_RANGE_SET = (1 << 1),
};
typedef struct ArrowWidget {
wmWidget widget;
WidgetCommonData data;
int style;
int flag;
float len; /* arrow line length */
float direction[3];
float up[3];
float aspect[2]; /* cone style only */
} ArrowWidget;
/* -------------------------------------------------------------------- */
static void widget_arrow_get_final_pos(wmWidget *widget, float r_pos[3])
{
ArrowWidget *arrow = (ArrowWidget *)widget;
mul_v3_v3fl(r_pos, arrow->direction, arrow->data.offset);
add_v3_v3(r_pos, arrow->widget.origin);
}
static void arrow_draw_geom(const ArrowWidget *arrow, const bool select)
{
if (arrow->style & WIDGET_ARROW_STYLE_CROSS) {
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_LIGHTING);
glBegin(GL_LINES);
glVertex2f(-1.0, 0.f);
glVertex2f(1.0, 0.f);
glVertex2f(0.f, -1.0);
glVertex2f(0.f, 1.0);
glEnd();
glPopAttrib();
}
else if (arrow->style & WIDGET_ARROW_STYLE_CONE) {
const float unitx = arrow->aspect[0];
const float unity = arrow->aspect[1];
const float vec[4][3] = {
{-unitx, -unity, 0},
{ unitx, -unity, 0},
{ unitx, unity, 0},
{-unitx, unity, 0},
};
glLineWidth(arrow->widget.line_width);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vec);
glDrawArrays(GL_LINE_LOOP, 0, ARRAY_SIZE(vec));
glDisableClientState(GL_VERTEX_ARRAY);
glLineWidth(1.0);
}
else {
#ifdef WIDGET_USE_CUSTOM_ARROWS
widget_draw_intern(&arrow_head_draw_info, select);
#else
const float vec[2][3] = {
{0.0f, 0.0f, 0.0f},
{0.0f, 0.0f, arrow->len},
};
glLineWidth(arrow->widget.line_width);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vec);
glDrawArrays(GL_LINE_STRIP, 0, ARRAY_SIZE(vec));
glDisableClientState(GL_VERTEX_ARRAY);
glLineWidth(1.0);
/* *** draw arrow head *** */
glPushMatrix();
if (arrow->style & WIDGET_ARROW_STYLE_BOX) {
const float size = 0.05f;
/* translate to line end with some extra offset so box starts exactly where line ends */
glTranslatef(0.0f, 0.0f, arrow->len + size);
/* scale down to box size */
glScalef(size, size, size);
/* draw cube */
widget_draw_intern(&cube_draw_info, select);
}
else {
const float len = 0.25f;
const float width = 0.06f;
const bool use_lighting = select == false && ((U.widget_flag & V3D_SHADED_WIDGETS) != 0);
/* translate to line end */
glTranslatef(0.0f, 0.0f, arrow->len);
if (use_lighting) {
glShadeModel(GL_SMOOTH);
}
GLUquadricObj *qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, GLU_FILL);
gluQuadricOrientation(qobj, GLU_INSIDE);
gluDisk(qobj, 0.0, width, 8, 1);
gluQuadricOrientation(qobj, GLU_OUTSIDE);
gluCylinder(qobj, width, 0.0, len, 8, 1);
gluDeleteQuadric(qobj);
if (use_lighting) {
glShadeModel(GL_FLAT);
}
}
glPopMatrix();
#endif
}
}
static void arrow_draw_intern(ArrowWidget *arrow, const bool select, const bool highlight)
{
const float up[3] = {0.0f, 0.0f, 1.0f};
float rot[3][3];
float mat[4][4];
float final_pos[3];
widget_arrow_get_final_pos(&arrow->widget, final_pos);
if (arrow->flag & ARROW_UP_VECTOR_SET) {
copy_v3_v3(rot[2], arrow->direction);
copy_v3_v3(rot[1], arrow->up);
cross_v3_v3v3(rot[0], arrow->up, arrow->direction);
}
else {
rotation_between_vecs_to_mat3(rot, up, arrow->direction);
}
copy_m4_m3(mat, rot);
copy_v3_v3(mat[3], final_pos);
mul_mat3_m4_fl(mat, arrow->widget.scale);
glPushMatrix();
glMultMatrixf(mat);
if (highlight && !(arrow->widget.flag & WM_WIDGET_DRAW_HOVER)) {
glColor4fv(arrow->widget.col_hi);
}
else {
glColor4fv(arrow->widget.col);
}
glEnable(GL_BLEND);
glTranslate3fv(arrow->widget.offset);
arrow_draw_geom(arrow, select);
glDisable(GL_BLEND);
glPopMatrix();
if (arrow->widget.interaction_data) {
WidgetInteraction *inter = arrow->widget.interaction_data;
copy_m4_m3(mat, rot);
copy_v3_v3(mat[3], inter->init_origin);
mul_mat3_m4_fl(mat, inter->init_scale);
glPushMatrix();
glMultMatrixf(mat);
glEnable(GL_BLEND);
glColor4f(0.5f, 0.5f, 0.5f, 0.5f);
glTranslate3fv(arrow->widget.offset);
arrow_draw_geom(arrow, select);
glDisable(GL_BLEND);
glPopMatrix();
}
}
static void widget_arrow_render_3d_intersect(const bContext *UNUSED(C), wmWidget *widget, int selectionbase)
{
GPU_select_load_id(selectionbase);
arrow_draw_intern((ArrowWidget *)widget, true, false);
}
static void widget_arrow_draw(const bContext *UNUSED(C), wmWidget *widget)
{
arrow_draw_intern((ArrowWidget *)widget, false, (widget->flag & WM_WIDGET_HIGHLIGHT) != 0);
}
/**
* Calculate arrow offset independent from prop min value,
* meaning the range will not be offset by min value first.
*/
#define USE_ABS_HANDLE_RANGE
static int widget_arrow_handler(bContext *C, const wmEvent *event, wmWidget *widget, const int flag)
{
ArrowWidget *arrow = (ArrowWidget *)widget;
WidgetInteraction *inter = widget->interaction_data;
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
float orig_origin[4];
float viewvec[3], tangent[3], plane[3];
float offset[4];
float m_diff[2];
float dir_2d[2], dir2d_final[2];
float facdir = 1.0f;
bool use_vertical = false;
copy_v3_v3(orig_origin, inter->init_origin);
orig_origin[3] = 1.0f;
add_v3_v3v3(offset, orig_origin, arrow->direction);
offset[3] = 1.0f;
/* calculate view vector */
if (rv3d->is_persp) {
sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]);
}
else {
copy_v3_v3(viewvec, rv3d->viewinv[2]);
}
normalize_v3(viewvec);
/* first determine if view vector is really close to the direction. If it is, we use
* vertical movement to determine offset, just like transform system does */
if (RAD2DEG(acos(dot_v3v3(viewvec, arrow->direction))) > 5.0f) {
/* multiply to projection space */
mul_m4_v4(rv3d->persmat, orig_origin);
mul_v4_fl(orig_origin, 1.0f / orig_origin[3]);
mul_m4_v4(rv3d->persmat, offset);
mul_v4_fl(offset, 1.0f / offset[3]);
sub_v2_v2v2(dir_2d, offset, orig_origin);
dir_2d[0] *= ar->winx;
dir_2d[1] *= ar->winy;
normalize_v2(dir_2d);
}
else {
dir_2d[0] = 0.0f;
dir_2d[1] = 1.0f;
use_vertical = true;
}
/* find mouse difference */
m_diff[0] = event->mval[0] - inter->init_mval[0];
m_diff[1] = event->mval[1] - inter->init_mval[1];
/* project the displacement on the screen space arrow direction */
project_v2_v2v2(dir2d_final, m_diff, dir_2d);
float zfac = ED_view3d_calc_zfac(rv3d, orig_origin, NULL);
ED_view3d_win_to_delta(ar, dir2d_final, offset, zfac);
add_v3_v3v3(orig_origin, offset, inter->init_origin);
/* calculate view vector for the new position */
if (rv3d->is_persp) {
sub_v3_v3v3(viewvec, orig_origin, rv3d->viewinv[3]);
}
else {
copy_v3_v3(viewvec, rv3d->viewinv[2]);
}
normalize_v3(viewvec);
if (!use_vertical) {
float fac;
/* now find a plane parallel to the view vector so we can intersect with the arrow direction */
cross_v3_v3v3(tangent, viewvec, offset);
cross_v3_v3v3(plane, tangent, viewvec);
fac = dot_v3v3(plane, offset) / dot_v3v3(arrow->direction, plane);
facdir = (fac < 0.0) ? -1.0 : 1.0;
mul_v3_v3fl(offset, arrow->direction, fac);
}
else {
facdir = (m_diff[1] < 0.0) ? -1.0 : 1.0;
}
WidgetCommonData *data = &arrow->data;
const float ofs_new = facdir * len_v3(offset);
const int slot = ARROW_SLOT_OFFSET_WORLD_SPACE;
/* set the property for the operator and call its modal function */
if (widget->props[slot]) {
const bool constrained = arrow->style & WIDGET_ARROW_STYLE_CONSTRAINED;
const bool inverted = arrow->style & WIDGET_ARROW_STYLE_INVERTED;
const bool use_precision = flag & WM_WIDGET_TWEAK_PRECISE;
float value = widget_value_from_offset(data, inter, ofs_new, constrained, inverted, use_precision);
widget_property_value_set(C, widget, slot, value);
/* get clamped value */
value = widget_property_value_get(widget, slot);
data->offset = widget_offset_from_value(data, value, constrained, inverted);
}
else {
data->offset = ofs_new;
}
/* tag the region for redraw */
ED_region_tag_redraw(ar);
WM_event_add_mousemove(C);
return OPERATOR_PASS_THROUGH;
}
static int widget_arrow_invoke(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget)
{
ArrowWidget *arrow = (ArrowWidget *)widget;
WidgetInteraction *inter = MEM_callocN(sizeof(WidgetInteraction), __func__);
PointerRNA ptr = widget->ptr[ARROW_SLOT_OFFSET_WORLD_SPACE];
PropertyRNA *prop = widget->props[ARROW_SLOT_OFFSET_WORLD_SPACE];
if (prop) {
inter->init_value = RNA_property_float_get(&ptr, prop);
}
inter->init_offset = arrow->data.offset;
inter->init_mval[0] = event->mval[0];
inter->init_mval[1] = event->mval[1];
inter->init_scale = widget->scale;
widget_arrow_get_final_pos(widget, inter->init_origin);
widget->interaction_data = inter;
return OPERATOR_RUNNING_MODAL;
}
static void widget_arrow_prop_data_update(wmWidget *widget, const int slot)
{
ArrowWidget *arrow = (ArrowWidget *)widget;
widget_property_data_update(
widget, &arrow->data, slot,
arrow->style & WIDGET_ARROW_STYLE_CONSTRAINED,
arrow->style & WIDGET_ARROW_STYLE_INVERTED);
}
static void widget_arrow_exit(bContext *C, wmWidget *widget, const bool cancel)
{
if (!cancel)
return;
ArrowWidget *arrow = (ArrowWidget *)widget;
WidgetCommonData *data = &arrow->data;
WidgetInteraction *inter = widget->interaction_data;
widget_property_value_reset(C, widget, inter, ARROW_SLOT_OFFSET_WORLD_SPACE);
data->offset = inter->init_offset;
}
/* -------------------------------------------------------------------- */
/** \name Arrow Widget API
*
* \{ */
wmWidget *WIDGET_arrow_new(wmWidgetGroup *wgroup, const char *name, const int style)
{
int real_style = style;
#ifdef WIDGET_USE_CUSTOM_ARROWS
if (!arrow_head_draw_info.init) {
arrow_head_draw_info.nverts = _WIDGET_nverts_arrow,
arrow_head_draw_info.ntris = _WIDGET_ntris_arrow,
arrow_head_draw_info.verts = _WIDGET_verts_arrow,
arrow_head_draw_info.normals = _WIDGET_normals_arrow,
arrow_head_draw_info.indices = _WIDGET_indices_arrow,
arrow_head_draw_info.init = true;
}
#endif
if (!cube_draw_info.init) {
cube_draw_info.nverts = _WIDGET_nverts_cube,
cube_draw_info.ntris = _WIDGET_ntris_cube,
cube_draw_info.verts = _WIDGET_verts_cube,
cube_draw_info.normals = _WIDGET_normals_cube,
cube_draw_info.indices = _WIDGET_indices_cube,
cube_draw_info.init = true;
}
/* inverted only makes sense in a constrained arrow */
if (real_style & WIDGET_ARROW_STYLE_INVERTED) {
real_style |= WIDGET_ARROW_STYLE_CONSTRAINED;
}
ArrowWidget *arrow = MEM_callocN(sizeof(ArrowWidget), name);
const float dir_default[3] = {0.0f, 0.0f, 1.0f};
arrow->widget.draw = widget_arrow_draw;
arrow->widget.get_final_position = widget_arrow_get_final_pos;
arrow->widget.intersect = NULL;
arrow->widget.handler = widget_arrow_handler;
arrow->widget.invoke = widget_arrow_invoke;
arrow->widget.render_3d_intersection = widget_arrow_render_3d_intersect;
arrow->widget.prop_data_update = widget_arrow_prop_data_update;
arrow->widget.exit = widget_arrow_exit;
arrow->widget.flag |= (WM_WIDGET_SCALE_3D | WM_WIDGET_DRAW_ACTIVE);
arrow->style = real_style;
arrow->len = 1.0f;
arrow->data.range_fac = 1.0f;
copy_v3_v3(arrow->direction, dir_default);
wm_widget_register(wgroup, &arrow->widget, name);
return (wmWidget *)arrow;
}
/**
* Define direction the arrow will point towards
*/
void WIDGET_arrow_set_direction(wmWidget *widget, const float direction[3])
{
ArrowWidget *arrow = (ArrowWidget *)widget;
copy_v3_v3(arrow->direction, direction);
normalize_v3(arrow->direction);
}
/**
* Define up-direction of the arrow widget
*/
void WIDGET_arrow_set_up_vector(wmWidget *widget, const float direction[3])
{
ArrowWidget *arrow = (ArrowWidget *)widget;
if (direction) {
copy_v3_v3(arrow->up, direction);
normalize_v3(arrow->up);
arrow->flag |= ARROW_UP_VECTOR_SET;
}
else {
arrow->flag &= ~ARROW_UP_VECTOR_SET;
}
}
/**
* Define a custom arrow line length
*/
void WIDGET_arrow_set_line_len(wmWidget *widget, const float len)
{
ArrowWidget *arrow = (ArrowWidget *)widget;
arrow->len = len;
}
/**
* Define a custom property UI range
*
* \note Needs to be called before WM_widget_set_property!
*/
void WIDGET_arrow_set_ui_range(wmWidget *widget, const float min, const float max)
{
ArrowWidget *arrow = (ArrowWidget *)widget;
BLI_assert(min < max);
BLI_assert(!(arrow->widget.props[0] && "Make sure this function is called before WM_widget_set_property"));
arrow->data.range = max - min;
arrow->data.min = min;
arrow->data.flag |= WIDGET_CUSTOM_RANGE_SET;
}
/**
* Define a custom factor for arrow min/max distance
*
* \note Needs to be called before WM_widget_set_property!
*/
void WIDGET_arrow_set_range_fac(wmWidget *widget, const float range_fac)
{
ArrowWidget *arrow = (ArrowWidget *)widget;
BLI_assert(!(arrow->widget.props[0] && "Make sure this function is called before WM_widget_set_property"));
arrow->data.range_fac = range_fac;
}
/**
* Define xy-aspect for arrow cone
*/
void WIDGET_arrow_cone_set_aspect(wmWidget *widget, const float aspect[2])
{
ArrowWidget *arrow = (ArrowWidget *)widget;
copy_v2_v2(arrow->aspect, aspect);
}
/** \} */ /* Arrow Widget API */
/* -------------------------------------------------------------------- */
void fix_linking_widget_arrow(void)
{
(void)0;
}

View File

@@ -0,0 +1,559 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2014 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/cage_widget.c
* \ingroup wm
*
* \name Cage Widget
*
* 2D Widget
*
* \brief Rectangular widget acting as a 'cage' around its content.
* Interacting scales or translates the widget.
*/
#include "BIF_gl.h"
#include "BKE_context.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "ED_screen.h"
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
/* own includes */
#include "wm_widget_wmapi.h"
#include "wm_widget_intern.h"
/* wmWidget->highlighted_part */
enum {
WIDGET_RECT_TRANSFORM_INTERSECT_TRANSLATE = 1,
WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT = 2,
WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT = 3,
WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_UP = 4,
WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN = 5
};
#define WIDGET_RECT_MIN_WIDTH 15.0f
#define WIDGET_RESIZER_WIDTH 20.0f
typedef struct RectTransformWidget {
wmWidget widget;
float w, h; /* dimensions of widget */
float rotation; /* rotation of the rectangle */
float scale[2]; /* scaling for the widget for non-destructive editing. */
int style;
} RectTransformWidget;
/* -------------------------------------------------------------------- */
static void rect_transform_draw_corners(rctf *r, const float offsetx, const float offsety)
{
glBegin(GL_LINES);
glVertex2f(r->xmin, r->ymin + offsety);
glVertex2f(r->xmin, r->ymin);
glVertex2f(r->xmin, r->ymin);
glVertex2f(r->xmin + offsetx, r->ymin);
glVertex2f(r->xmax, r->ymin + offsety);
glVertex2f(r->xmax, r->ymin);
glVertex2f(r->xmax, r->ymin);
glVertex2f(r->xmax - offsetx, r->ymin);
glVertex2f(r->xmax, r->ymax - offsety);
glVertex2f(r->xmax, r->ymax);
glVertex2f(r->xmax, r->ymax);
glVertex2f(r->xmax - offsetx, r->ymax);
glVertex2f(r->xmin, r->ymax - offsety);
glVertex2f(r->xmin, r->ymax);
glVertex2f(r->xmin, r->ymax);
glVertex2f(r->xmin + offsetx, r->ymax);
glEnd();
}
static void rect_transform_draw_interaction(
const float col[4], const int highlighted,
const float half_w, const float half_h,
const float w, const float h, const float line_width)
{
float verts[4][2];
switch (highlighted) {
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT:
verts[0][0] = -half_w + w;
verts[0][1] = -half_h;
verts[1][0] = -half_w;
verts[1][1] = -half_h;
verts[2][0] = -half_w;
verts[2][1] = half_h;
verts[3][0] = -half_w + w;
verts[3][1] = half_h;
break;
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT:
verts[0][0] = half_w - w;
verts[0][1] = -half_h;
verts[1][0] = half_w;
verts[1][1] = -half_h;
verts[2][0] = half_w;
verts[2][1] = half_h;
verts[3][0] = half_w - w;
verts[3][1] = half_h;
break;
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN:
verts[0][0] = -half_w;
verts[0][1] = -half_h + h;
verts[1][0] = -half_w;
verts[1][1] = -half_h;
verts[2][0] = half_w;
verts[2][1] = -half_h;
verts[3][0] = half_w;
verts[3][1] = -half_h + h;
break;
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_UP:
verts[0][0] = -half_w;
verts[0][1] = half_h - h;
verts[1][0] = -half_w;
verts[1][1] = half_h;
verts[2][0] = half_w;
verts[2][1] = half_h;
verts[3][0] = half_w;
verts[3][1] = half_h - h;
break;
default:
return;
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, verts);
glLineWidth(line_width + 3.0);
glColor3f(0.0, 0.0, 0.0);
glDrawArrays(GL_LINE_STRIP, 0, 3);
glLineWidth(line_width);
glColor3fv(col);
glDrawArrays(GL_LINE_STRIP, 0, 3);
glLineWidth(1.0);
}
static void widget_rect_transform_draw(const bContext *UNUSED(C), wmWidget *widget)
{
RectTransformWidget *cage = (RectTransformWidget *)widget;
rctf r;
float w = cage->w;
float h = cage->h;
float aspx = 1.0f, aspy = 1.0f;
const float half_w = w / 2.0f;
const float half_h = h / 2.0f;
r.xmin = -half_w;
r.ymin = -half_h;
r.xmax = half_w;
r.ymax = half_h;
glPushMatrix();
glTranslatef(widget->origin[0] + widget->offset[0], widget->origin[1] + widget->offset[1], 0.0f);
if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM)
glScalef(cage->scale[0], cage->scale[0], 1.0);
else
glScalef(cage->scale[0], cage->scale[1], 1.0);
if (w > h)
aspx = h / w;
else
aspy = w / h;
w = min_ff(aspx * w / WIDGET_RESIZER_WIDTH, WIDGET_RESIZER_WIDTH / cage->scale[0]);
h = min_ff(aspy * h / WIDGET_RESIZER_WIDTH, WIDGET_RESIZER_WIDTH /
((cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) ? cage->scale[0] : cage->scale[1]));
/* corner widgets */
glColor3f(0.0, 0.0, 0.0);
glLineWidth(cage->widget.line_width + 3.0f);
rect_transform_draw_corners(&r, w, h);
/* corner widgets */
glColor3fv(widget->col);
glLineWidth(cage->widget.line_width);
rect_transform_draw_corners(&r, w, h);
rect_transform_draw_interaction(widget->col, widget->highlighted_part, half_w, half_h,
w, h, cage->widget.line_width);
glLineWidth(1.0);
glPopMatrix();
}
static int widget_rect_transform_get_cursor(wmWidget *widget)
{
switch (widget->highlighted_part) {
case WIDGET_RECT_TRANSFORM_INTERSECT_TRANSLATE:
return BC_HANDCURSOR;
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT:
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT:
return CURSOR_X_MOVE;
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN:
case WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_UP:
return CURSOR_Y_MOVE;
default:
return CURSOR_STD;
}
}
static int widget_rect_transform_intersect(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget)
{
RectTransformWidget *cage = (RectTransformWidget *)widget;
const float mouse[2] = {event->mval[0], event->mval[1]};
//float matrot[2][2];
float point_local[2];
float w = cage->w;
float h = cage->h;
float half_w = w / 2.0f;
float half_h = h / 2.0f;
float aspx = 1.0f, aspy = 1.0f;
/* rotate mouse in relation to the center and relocate it */
sub_v2_v2v2(point_local, mouse, widget->origin);
point_local[0] -= widget->offset[0];
point_local[1] -= widget->offset[1];
//rotate_m2(matrot, -cage->transform.rotation);
if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM)
mul_v2_fl(point_local, 1.0f / cage->scale[0]);
else {
point_local[0] /= cage->scale[0];
point_local[1] /= cage->scale[0];
}
if (cage->w > cage->h)
aspx = h / w;
else
aspy = w / h;
w = min_ff(aspx * w / WIDGET_RESIZER_WIDTH, WIDGET_RESIZER_WIDTH / cage->scale[0]);
h = min_ff(aspy * h / WIDGET_RESIZER_WIDTH, WIDGET_RESIZER_WIDTH /
((cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) ? cage->scale[0] : cage->scale[1]));
rctf r;
r.xmin = -half_w + w;
r.ymin = -half_h + h;
r.xmax = half_w - w;
r.ymax = half_h - h;
bool isect = BLI_rctf_isect_pt_v(&r, point_local);
if (isect)
return WIDGET_RECT_TRANSFORM_INTERSECT_TRANSLATE;
/* if widget does not have a scale intersection, don't do it */
if (cage->style & (WIDGET_RECT_TRANSFORM_STYLE_SCALE | WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM)) {
r.xmin = -half_w;
r.ymin = -half_h;
r.xmax = -half_w + w;
r.ymax = half_h;
isect = BLI_rctf_isect_pt_v(&r, point_local);
if (isect)
return WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT;
r.xmin = half_w - w;
r.ymin = -half_h;
r.xmax = half_w;
r.ymax = half_h;
isect = BLI_rctf_isect_pt_v(&r, point_local);
if (isect)
return WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT;
r.xmin = -half_w;
r.ymin = -half_h;
r.xmax = half_w;
r.ymax = -half_h + h;
isect = BLI_rctf_isect_pt_v(&r, point_local);
if (isect)
return WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN;
r.xmin = -half_w;
r.ymin = half_h - h;
r.xmax = half_w;
r.ymax = half_h;
isect = BLI_rctf_isect_pt_v(&r, point_local);
if (isect)
return WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_UP;
}
return 0;
}
typedef struct RectTransformInteraction {
float orig_mouse[2];
float orig_offset[2];
float orig_scale[2];
} RectTransformInteraction;
static bool widget_rect_transform_get_prop_value(wmWidget *widget, const int slot, float *value)
{
PropertyType type = RNA_property_type(widget->props[slot]);
if (type != PROP_FLOAT) {
fprintf(stderr, "Rect Transform widget can only be bound to float properties");
return false;
}
else {
if (slot == RECT_TRANSFORM_SLOT_OFFSET) {
if (RNA_property_array_length(&widget->ptr[slot], widget->props[slot]) != 2) {
fprintf(stderr, "Rect Transform widget offset not only be bound to array float property");
return false;
}
RNA_property_float_get_array(&widget->ptr[slot], widget->props[slot], value);
}
else if (slot == RECT_TRANSFORM_SLOT_SCALE) {
RectTransformWidget *cage = (RectTransformWidget *)widget;
if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) {
*value = RNA_property_float_get(&widget->ptr[slot], widget->props[slot]);
}
else {
if (RNA_property_array_length(&widget->ptr[slot], widget->props[slot]) != 2) {
fprintf(stderr, "Rect Transform widget scale not only be bound to array float property");
return false;
}
RNA_property_float_get_array(&widget->ptr[slot], widget->props[slot], value);
}
}
}
return true;
}
static int widget_rect_transform_invoke(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget)
{
RectTransformWidget *cage = (RectTransformWidget *)widget;
RectTransformInteraction *data = MEM_callocN(sizeof(RectTransformInteraction), "cage_interaction");
copy_v2_v2(data->orig_offset, widget->offset);
copy_v2_v2(data->orig_scale, cage->scale);
data->orig_mouse[0] = event->mval[0];
data->orig_mouse[1] = event->mval[1];
widget->interaction_data = data;
return OPERATOR_RUNNING_MODAL;
}
static int widget_rect_transform_handler(bContext *C, const wmEvent *event, wmWidget *widget, const int UNUSED(flag))
{
RectTransformWidget *cage = (RectTransformWidget *)widget;
RectTransformInteraction *data = widget->interaction_data;
/* needed here as well in case clamping occurs */
const float orig_ofx = widget->offset[0], orig_ofy = widget->offset[1];
const float valuex = (event->mval[0] - data->orig_mouse[0]);
const float valuey = (event->mval[1] - data->orig_mouse[1]);
if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_TRANSLATE) {
widget->offset[0] = data->orig_offset[0] + valuex;
widget->offset[1] = data->orig_offset[1] + valuey;
}
else if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_LEFT) {
widget->offset[0] = data->orig_offset[0] + valuex / 2.0;
cage->scale[0] = (cage->w * data->orig_scale[0] - valuex) / cage->w;
}
else if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_SCALEX_RIGHT) {
widget->offset[0] = data->orig_offset[0] + valuex / 2.0;
cage->scale[0] = (cage->w * data->orig_scale[0] + valuex) / cage->w;
}
else if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_DOWN) {
widget->offset[1] = data->orig_offset[1] + valuey / 2.0;
if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) {
cage->scale[0] = (cage->h * data->orig_scale[0] - valuey) / cage->h;
}
else {
cage->scale[1] = (cage->h * data->orig_scale[1] - valuey) / cage->h;
}
}
else if (widget->highlighted_part == WIDGET_RECT_TRANSFORM_INTERSECT_SCALEY_UP) {
widget->offset[1] = data->orig_offset[1] + valuey / 2.0;
if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) {
cage->scale[0] = (cage->h * data->orig_scale[0] + valuey) / cage->h;
}
else {
cage->scale[1] = (cage->h * data->orig_scale[1] + valuey) / cage->h;
}
}
/* clamping - make sure widget is at least 5 pixels wide */
if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) {
if (cage->scale[0] < WIDGET_RECT_MIN_WIDTH / cage->h ||
cage->scale[0] < WIDGET_RECT_MIN_WIDTH / cage->w)
{
cage->scale[0] = max_ff(WIDGET_RECT_MIN_WIDTH / cage->h, WIDGET_RECT_MIN_WIDTH / cage->w);
widget->offset[0] = orig_ofx;
widget->offset[1] = orig_ofy;
}
}
else {
if (cage->scale[0] < WIDGET_RECT_MIN_WIDTH / cage->w) {
cage->scale[0] = WIDGET_RECT_MIN_WIDTH / cage->w;
widget->offset[0] = orig_ofx;
}
if (cage->scale[1] < WIDGET_RECT_MIN_WIDTH / cage->h) {
cage->scale[1] = WIDGET_RECT_MIN_WIDTH / cage->h;
widget->offset[1] = orig_ofy;
}
}
if (widget->props[RECT_TRANSFORM_SLOT_OFFSET]) {
PointerRNA ptr = widget->ptr[RECT_TRANSFORM_SLOT_OFFSET];
PropertyRNA *prop = widget->props[RECT_TRANSFORM_SLOT_OFFSET];
RNA_property_float_set_array(&ptr, prop, widget->offset);
RNA_property_update(C, &ptr, prop);
}
if (widget->props[RECT_TRANSFORM_SLOT_SCALE]) {
PointerRNA ptr = widget->ptr[RECT_TRANSFORM_SLOT_SCALE];
PropertyRNA *prop = widget->props[RECT_TRANSFORM_SLOT_SCALE];
if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) {
RNA_property_float_set(&ptr, prop, cage->scale[0]);
}
else {
RNA_property_float_set_array(&ptr, prop, cage->scale);
}
RNA_property_update(C, &ptr, prop);
}
/* tag the region for redraw */
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_PASS_THROUGH;
}
static void widget_rect_transform_prop_data_update(wmWidget *widget, const int slot)
{
RectTransformWidget *cage = (RectTransformWidget *)widget;
if (slot == RECT_TRANSFORM_SLOT_OFFSET)
widget_rect_transform_get_prop_value(widget, RECT_TRANSFORM_SLOT_OFFSET, widget->offset);
if (slot == RECT_TRANSFORM_SLOT_SCALE)
widget_rect_transform_get_prop_value(widget, RECT_TRANSFORM_SLOT_SCALE, cage->scale);
}
static void widget_rect_transform_exit(bContext *C, wmWidget *widget, const bool cancel)
{
RectTransformWidget *cage = (RectTransformWidget *)widget;
RectTransformInteraction *data = widget->interaction_data;
if (!cancel)
return;
/* reset properties */
if (widget->props[RECT_TRANSFORM_SLOT_OFFSET]) {
PointerRNA ptr = widget->ptr[RECT_TRANSFORM_SLOT_OFFSET];
PropertyRNA *prop = widget->props[RECT_TRANSFORM_SLOT_OFFSET];
RNA_property_float_set_array(&ptr, prop, data->orig_offset);
RNA_property_update(C, &ptr, prop);
}
if (widget->props[RECT_TRANSFORM_SLOT_SCALE]) {
PointerRNA ptr = widget->ptr[RECT_TRANSFORM_SLOT_SCALE];
PropertyRNA *prop = widget->props[RECT_TRANSFORM_SLOT_SCALE];
if (cage->style & WIDGET_RECT_TRANSFORM_STYLE_SCALE_UNIFORM) {
RNA_property_float_set(&ptr, prop, data->orig_scale[0]);
}
else {
RNA_property_float_set_array(&ptr, prop, data->orig_scale);
}
RNA_property_update(C, &ptr, prop);
}
}
/* -------------------------------------------------------------------- */
/** \name Cage Widget API
*
* \{ */
wmWidget *WIDGET_rect_transform_new(wmWidgetGroup *wgroup, const char *name, const int style)
{
RectTransformWidget *cage = MEM_callocN(sizeof(RectTransformWidget), name);
cage->widget.draw = widget_rect_transform_draw;
cage->widget.invoke = widget_rect_transform_invoke;
cage->widget.prop_data_update = widget_rect_transform_prop_data_update;
cage->widget.handler = widget_rect_transform_handler;
cage->widget.intersect = widget_rect_transform_intersect;
cage->widget.exit = widget_rect_transform_exit;
cage->widget.get_cursor = widget_rect_transform_get_cursor;
cage->widget.max_prop = 2;
cage->widget.flag |= WM_WIDGET_DRAW_ACTIVE;
cage->scale[0] = cage->scale[1] = 1.0f;
cage->style = style;
wm_widget_register(wgroup, &cage->widget, name);
return (wmWidget *)cage;
}
void WIDGET_rect_transform_set_dimensions(wmWidget *widget, const float width, const float height)
{
RectTransformWidget *cage = (RectTransformWidget *)widget;
cage->w = width;
cage->h = height;
}
/** \} */ // Cage Widget API
/* -------------------------------------------------------------------- */
void fix_linking_widget_cage(void)
{
(void)0;
}

View File

@@ -0,0 +1,348 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2014 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/dial_widget.c
* \ingroup wm
*
* \name Dial Widget
*
* 3D Widget
*
* \brief Circle shaped widget for circular interaction.
* Currently no own handling, use with operator only.
*/
#include "BIF_gl.h"
#include "BKE_context.h"
#include "BLI_math.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "GPU_select.h"
#include "MEM_guardedalloc.h"
#include "WM_api.h"
#include "WM_types.h"
/* own includes */
#include "WM_widget_types.h"
#include "WM_widget_library.h"
#include "wm_widget_wmapi.h"
#include "wm_widget_intern.h"
#include "widget_geometry.h"
#include "widget_library_intern.h"
/* to use custom dials exported to dial_widget.c */
//#define WIDGET_USE_CUSTOM_DIAS
#ifdef WIDGET_USE_CUSTOM_DIAS
WidgetDrawInfo dial_draw_info = {0};
#endif
typedef struct DialWidget {
wmWidget widget;
int style;
float direction[3];
} DialWidget;
typedef struct DialInteraction {
float init_mval[2];
/* cache the last angle to detect rotations bigger than -/+ PI */
float last_angle;
/* number of full rotations */
int rotations;
} DialInteraction;
#define DIAL_WIDTH 1.0f
#define DIAL_RESOLUTION 32
/* -------------------------------------------------------------------- */
static void dial_geom_draw(const DialWidget *dial, const float col[4], const bool select)
{
#ifdef WIDGET_USE_CUSTOM_DIAS
widget_draw_intern(&dial_draw_info, select);
#else
const bool filled = (dial->style == WIDGET_DIAL_STYLE_RING_FILLED);
glLineWidth(dial->widget.line_width);
glColor4fv(col);
GLUquadricObj *qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj, filled ? GLU_FILL : GLU_SILHOUETTE);
/* inner at 0.0 with silhouette drawing confuses OGL selection, so draw it at width */
gluDisk(qobj, filled ? 0.0 : DIAL_WIDTH, DIAL_WIDTH, DIAL_RESOLUTION, 1);
gluDeleteQuadric(qobj);
UNUSED_VARS(select);
#endif
}
/**
* Draws a line from (0, 0, 0) to \a co_outer, at \a angle.
*/
static void dial_ghostarc_draw_helpline(const float angle, const float co_outer[3])
{
glLineWidth(1.0f);
glPushMatrix();
glRotatef(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f);
// glScalef(0.0f, DIAL_WIDTH - dial->widget.line_width * 0.5f / U.widget_scale, 0.0f);
glBegin(GL_LINE_STRIP);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3fv(co_outer);
glEnd();
glPopMatrix();
}
static void dial_ghostarc_draw(const DialWidget *dial, const float angle_ofs, const float angle_delta)
{
GLUquadricObj *qobj = gluNewQuadric();
const float width_inner = DIAL_WIDTH - dial->widget.line_width * 0.5f / U.widget_scale;
gluQuadricDrawStyle(qobj, GLU_FILL);
gluPartialDisk(qobj, 0.0, width_inner, DIAL_RESOLUTION, 1, RAD2DEGF(angle_ofs), RAD2DEGF(angle_delta));
gluDeleteQuadric(qobj);
}
static void dial_ghostarc_get_angles(
const DialWidget *dial, const wmEvent *event, const ARegion *ar,
float mat[4][4], const float co_outer[3],
float *r_start, float *r_delta)
{
DialInteraction *inter = dial->widget.interaction_data;
const RegionView3D *rv3d = ar->regiondata;
const float mval[2] = {event->x - ar->winrct.xmin, event->y - ar->winrct.ymin};
bool inv = false;
/* we might need to invert the direction of the angles */
float view_vec[3], axis_vec[3];
ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
normalize_v3_v3(axis_vec, dial->direction);
if (dot_v3v3(view_vec, axis_vec) < 0.0f) {
inv = true;
}
float co[3], origin2d[2], co2d[2];
mul_v3_project_m4_v3(co, mat, co_outer);
/* project 3d coordinats to 2d viewplane */
ED_view3d_project_float_global(ar, dial->widget.origin, origin2d, V3D_PROJ_TEST_NOP);
ED_view3d_project_float_global(ar, co, co2d, V3D_PROJ_TEST_NOP);
/* convert to widget relative space */
float rel_initmval[2], rel_mval[2], rel_co[2];
sub_v2_v2v2(rel_initmval, inter->init_mval, origin2d);
sub_v2_v2v2(rel_mval, mval, origin2d);
sub_v2_v2v2(rel_co, co2d, origin2d);
/* return angles */
const float start = angle_signed_v2v2(rel_co, rel_initmval) * (inv ? -1 : 1);
const float delta = angle_signed_v2v2(rel_initmval, rel_mval) * (inv ? -1 : 1);
/* Change of sign, we passed the 180 degree threshold. This means we need to add a turn
* to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2.
* Logic taken from BLI_dial_angle */
if ((delta * inter->last_angle < 0.0f) &&
(fabsf(inter->last_angle) > (float)M_PI_2))
{
if (inter->last_angle < 0.0f)
inter->rotations--;
else
inter->rotations++;
}
inter->last_angle = delta;
*r_start = start;
*r_delta = fmod(delta + 2.0f * (float)M_PI * inter->rotations, 2 * (float)M_PI);
}
static void dial_draw_intern(const bContext *C, DialWidget *dial, const bool select, const bool highlight)
{
float rot[3][3];
float mat[4][4];
const float up[3] = {0.0f, 0.0f, 1.0f};
const float *col = widget_color_get(&dial->widget, highlight);
BLI_assert(CTX_wm_area(C)->spacetype == SPACE_VIEW3D);
rotation_between_vecs_to_mat3(rot, up, dial->direction);
copy_m4_m3(mat, rot);
copy_v3_v3(mat[3], dial->widget.origin);
mul_mat3_m4_fl(mat, dial->widget.scale);
glPushMatrix();
glMultMatrixf(mat);
glTranslate3fv(dial->widget.offset);
/* draw rotation indicator arc first */
if ((dial->widget.flag & WM_WIDGET_DRAW_VALUE) && (dial->widget.flag & WM_WIDGET_ACTIVE)) {
wmWindow *win = CTX_wm_window(C);
const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f}; /* coordinate at which the arc drawing will be started */
float angle_ofs, angle_delta;
dial_ghostarc_get_angles(dial, win->eventstate, CTX_wm_region(C), mat, co_outer, &angle_ofs, &angle_delta);
/* draw! */
glColor4f(0.8f, 0.8f, 0.8f, 0.4f);
dial_ghostarc_draw(dial, angle_ofs, angle_delta);
glColor4fv(col);
dial_ghostarc_draw_helpline(angle_ofs, co_outer); /* starting position */
dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer); /* starting position + current value */
}
/* draw actual dial widget */
dial_geom_draw(dial, col, select);
glPopMatrix();
}
static void widget_dial_render_3d_intersect(const bContext *C, wmWidget *widget, int selectionbase)
{
DialWidget *dial = (DialWidget *)widget;
/* enable clipping if needed */
if (dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
double plane[4];
copy_v3db_v3fl(plane, rv3d->viewinv[2]);
plane[3] = -dot_v3v3(rv3d->viewinv[2], widget->origin);
glClipPlane(GL_CLIP_PLANE0, plane);
glEnable(GL_CLIP_PLANE0);
}
GPU_select_load_id(selectionbase);
dial_draw_intern(C, dial, true, false);
if (dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
glDisable(GL_CLIP_PLANE0);
}
}
static void widget_dial_draw(const bContext *C, wmWidget *widget)
{
DialWidget *dial = (DialWidget *)widget;
const bool active = widget->flag & WM_WIDGET_ACTIVE;
/* enable clipping if needed */
if (!active && dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
double plane[4];
ARegion *ar = CTX_wm_region(C);
RegionView3D *rv3d = ar->regiondata;
copy_v3db_v3fl(plane, rv3d->viewinv[2]);
plane[3] = -dot_v3v3(rv3d->viewinv[2], widget->origin);
glClipPlane(GL_CLIP_PLANE0, plane);
glEnable(GL_CLIP_PLANE0);
}
glEnable(GL_BLEND);
dial_draw_intern(C, dial, false, (widget->flag & WM_WIDGET_HIGHLIGHT) != 0);
glDisable(GL_BLEND);
if (!active && dial->style == WIDGET_DIAL_STYLE_RING_CLIPPED) {
glDisable(GL_CLIP_PLANE0);
}
}
static int widget_dial_invoke(bContext *UNUSED(C), const wmEvent *event, wmWidget *widget)
{
DialInteraction *inter = MEM_callocN(sizeof(DialInteraction), __func__);
inter->init_mval[0] = event->mval[0];
inter->init_mval[1] = event->mval[1];
widget->interaction_data = inter;
return OPERATOR_RUNNING_MODAL;
}
/* -------------------------------------------------------------------- */
/** \name Dial Widget API
*
* \{ */
wmWidget *WIDGET_dial_new(wmWidgetGroup *wgroup, const char *name, const int style)
{
DialWidget *dial = MEM_callocN(sizeof(DialWidget), name);
const float dir_default[3] = {0.0f, 0.0f, 1.0f};
#ifdef WIDGET_USE_CUSTOM_DIAS
if (!dial_draw_info.init) {
dial_draw_info.nverts = _WIDGET_nverts_dial,
dial_draw_info.ntris = _WIDGET_ntris_dial,
dial_draw_info.verts = _WIDGET_verts_dial,
dial_draw_info.normals = _WIDGET_normals_dial,
dial_draw_info.indices = _WIDGET_indices_dial,
dial_draw_info.init = true;
}
#endif
dial->widget.draw = widget_dial_draw;
dial->widget.intersect = NULL;
dial->widget.render_3d_intersection = widget_dial_render_3d_intersect;
dial->widget.invoke = widget_dial_invoke;
dial->widget.flag |= WM_WIDGET_SCALE_3D;
dial->style = style;
/* defaults */
copy_v3_v3(dial->direction, dir_default);
wm_widget_register(wgroup, &dial->widget, name);
return (wmWidget *)dial;
}
/**
* Define up-direction of the dial widget
*/
void WIDGET_dial_set_up_vector(wmWidget *widget, const float direction[3])
{
DialWidget *dial = (DialWidget *)widget;
copy_v3_v3(dial->direction, direction);
normalize_v3(dial->direction);
}
/** \} */ // Dial Widget API
/* -------------------------------------------------------------------- */
void fix_linking_widget_dial(void)
{
(void)0;
}

View File

@@ -0,0 +1,137 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/geom_arrow_widget.c
* \ingroup wm
*/
int _WIDGET_nverts_arrow = 25;
int _WIDGET_ntris_arrow = 46;
float _WIDGET_verts_arrow[][3] = {
{-0.000000, 0.012320, 0.000000},
{-0.000000, 0.012320, 0.974306},
{0.008711, 0.008711, 0.000000},
{0.008711, 0.008711, 0.974306},
{0.012320, -0.000000, 0.000000},
{0.012320, -0.000000, 0.974306},
{0.008711, -0.008711, 0.000000},
{0.008711, -0.008711, 0.974306},
{-0.000000, -0.012320, 0.000000},
{-0.000000, -0.012320, 0.974306},
{-0.008711, -0.008711, 0.000000},
{-0.008711, -0.008711, 0.974306},
{-0.012320, 0.000000, 0.000000},
{-0.012320, 0.000000, 0.974306},
{-0.008711, 0.008711, 0.000000},
{-0.008711, 0.008711, 0.974306},
{0.000000, 0.072555, 0.974306},
{0.051304, 0.051304, 0.974306},
{0.072555, -0.000000, 0.974306},
{0.051304, -0.051304, 0.974306},
{-0.000000, -0.072555, 0.974306},
{-0.051304, -0.051304, 0.974306},
{-0.072555, 0.000000, 0.974306},
{-0.051304, 0.051304, 0.974306},
{0.000000, -0.000000, 1.268098},
};
float _WIDGET_normals_arrow[][3] = {
{0.000000, 0.776360, -0.630238},
{0.000000, 0.594348, -0.804163},
{0.548967, 0.548967, -0.630238},
{0.420270, 0.420270, -0.804163},
{0.776360, 0.000000, -0.630238},
{0.594378, 0.000000, -0.804163},
{0.548967, -0.548967, -0.630238},
{0.420270, -0.420270, -0.804163},
{0.000000, -0.776360, -0.630238},
{0.000000, -0.594378, -0.804163},
{-0.548967, -0.548967, -0.630238},
{-0.420270, -0.420270, -0.804163},
{-0.776360, 0.000000, -0.630238},
{-0.594378, 0.000000, -0.804163},
{-0.548967, 0.548967, -0.630238},
{-0.420270, 0.420270, -0.804163},
{0.000000, 0.843226, -0.537492},
{0.596271, 0.596271, -0.537492},
{0.843226, 0.000000, -0.537492},
{0.596271, -0.596271, -0.537492},
{0.000000, -0.843226, -0.537492},
{-0.596271, -0.596271, -0.537492},
{-0.843226, 0.000000, -0.537492},
{-0.596271, 0.596271, -0.537492},
{0.000000, 0.000000, 1.000000},
};
unsigned short _WIDGET_indices_arrow[] = {
1, 3, 2,
3, 5, 4,
5, 7, 6,
7, 9, 8,
9, 11, 10,
11, 13, 12,
5, 18, 19,
15, 1, 0,
13, 15, 14,
6, 10, 14,
11, 21, 22,
7, 19, 20,
13, 22, 23,
3, 17, 18,
9, 20, 21,
15, 23, 16,
1, 16, 17,
23, 22, 24,
21, 20, 24,
19, 18, 24,
17, 16, 24,
16, 23, 24,
22, 21, 24,
20, 19, 24,
18, 17, 24,
0, 1, 2,
2, 3, 4,
4, 5, 6,
6, 7, 8,
8, 9, 10,
10, 11, 12,
7, 5, 19,
14, 15, 0,
12, 13, 14,
14, 0, 2,
2, 4, 6,
6, 8, 10,
10, 12, 14,
14, 2, 6,
13, 11, 22,
9, 7, 20,
15, 13, 23,
5, 3, 18,
11, 9, 21,
1, 15, 16,
3, 1, 17,
};

View File

@@ -0,0 +1,69 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/geom_cube_widget.c
* \ingroup wm
*/
int _WIDGET_nverts_cube = 8;
int _WIDGET_ntris_cube = 12;
float _WIDGET_verts_cube[][3] = {
{1.000000, 1.000000, -1.000000},
{1.000000, -1.000000, -1.000000},
{-1.000000, -1.000000, -1.000000},
{-1.000000, 1.000000, -1.000000},
{1.000000, 1.000000, 1.000000},
{0.999999, -1.000001, 1.000000},
{-1.000000, -1.000000, 1.000000},
{-1.000000, 1.000000, 1.000000},
};
float _WIDGET_normals_cube[][3] = {
{0.577349, 0.577349, -0.577349},
{0.577349, -0.577349, -0.577349},
{-0.577349, -0.577349, -0.577349},
{-0.577349, 0.577349, -0.577349},
{0.577349, 0.577349, 0.577349},
{0.577349, -0.577349, 0.577349},
{-0.577349, -0.577349, 0.577349},
{-0.577349, 0.577349, 0.577349},
};
unsigned short _WIDGET_indices_cube[] = {
1, 2, 3,
7, 6, 5,
4, 5, 1,
5, 6, 2,
2, 6, 7,
0, 3, 7,
0, 1, 3,
4, 7, 5,
0, 4, 1,
1, 5, 2,
3, 2, 7,
4, 0, 7,
};

View File

@@ -0,0 +1,809 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/geom_dial_widget.c
* \ingroup wm
*/
int _WIDGET_nverts_dial = 192;
int _WIDGET_ntris_dial = 384;
float _WIDGET_verts_dial[][3] = {
{1.034000, 0.000000, 0.000000},
{1.017000, 0.000000, 0.029445},
{0.983000, 0.000000, 0.029445},
{0.966000, 0.000000, 0.000000},
{0.983000, 0.000000, -0.029445},
{1.017000, 0.000000, -0.029445},
{1.014132, 0.201723, 0.000000},
{0.997459, 0.198407, 0.029445},
{0.964112, 0.191774, 0.029445},
{0.947439, 0.188457, 0.000000},
{0.964112, 0.191774, -0.029445},
{0.997459, 0.198407, -0.029445},
{0.955292, 0.395695, 0.000000},
{0.939586, 0.389189, 0.029445},
{0.908174, 0.376178, 0.029445},
{0.892468, 0.369672, 0.000000},
{0.908174, 0.376178, -0.029445},
{0.939586, 0.389189, -0.029445},
{0.859740, 0.574460, 0.000000},
{0.845605, 0.565015, 0.029445},
{0.817335, 0.546126, 0.029445},
{0.803200, 0.536681, 0.000000},
{0.817335, 0.546126, -0.029445},
{0.845605, 0.565015, -0.029445},
{0.731148, 0.731148, 0.000000},
{0.719128, 0.719128, 0.029445},
{0.695086, 0.695086, 0.029445},
{0.683065, 0.683065, 0.000000},
{0.695086, 0.695086, -0.029445},
{0.719128, 0.719128, -0.029445},
{0.574460, 0.859740, 0.000000},
{0.565015, 0.845605, 0.029445},
{0.546125, 0.817335, 0.029445},
{0.536681, 0.803200, 0.000000},
{0.546125, 0.817335, -0.029445},
{0.565015, 0.845605, -0.029445},
{0.395695, 0.955291, 0.000000},
{0.389189, 0.939585, 0.029445},
{0.376178, 0.908173, 0.029445},
{0.369672, 0.892467, 0.000000},
{0.376178, 0.908173, -0.029445},
{0.389189, 0.939585, -0.029445},
{0.201724, 1.014132, 0.000000},
{0.198407, 0.997459, 0.029445},
{0.191774, 0.964112, 0.029445},
{0.188457, 0.947439, 0.000000},
{0.191774, 0.964112, -0.029445},
{0.198407, 0.997459, -0.029445},
{0.000000, 1.034000, 0.000000},
{0.000000, 1.017000, 0.029445},
{0.000000, 0.983000, 0.029445},
{0.000000, 0.966000, 0.000000},
{0.000000, 0.983000, -0.029445},
{0.000000, 1.017000, -0.029445},
{-0.201723, 1.014132, 0.000000},
{-0.198407, 0.997459, 0.029445},
{-0.191774, 0.964112, 0.029445},
{-0.188457, 0.947439, 0.000000},
{-0.191774, 0.964112, -0.029445},
{-0.198407, 0.997459, -0.029445},
{-0.395695, 0.955291, 0.000000},
{-0.389189, 0.939585, 0.029445},
{-0.376178, 0.908174, 0.029445},
{-0.369672, 0.892468, 0.000000},
{-0.376178, 0.908174, -0.029445},
{-0.389189, 0.939585, -0.029445},
{-0.574459, 0.859740, 0.000000},
{-0.565015, 0.845605, 0.029445},
{-0.546125, 0.817335, 0.029445},
{-0.536681, 0.803200, 0.000000},
{-0.546125, 0.817335, -0.029445},
{-0.565015, 0.845605, -0.029445},
{-0.731149, 0.731148, 0.000000},
{-0.719128, 0.719127, 0.029445},
{-0.695086, 0.695086, 0.029445},
{-0.683065, 0.683065, 0.000000},
{-0.695086, 0.695086, -0.029445},
{-0.719128, 0.719127, -0.029445},
{-0.859740, 0.574460, 0.000000},
{-0.845604, 0.565015, 0.029445},
{-0.817335, 0.546126, 0.029445},
{-0.803200, 0.536681, 0.000000},
{-0.817335, 0.546126, -0.029445},
{-0.845604, 0.565015, -0.029445},
{-0.955291, 0.395695, 0.000000},
{-0.939585, 0.389189, 0.029445},
{-0.908173, 0.376178, 0.029445},
{-0.892468, 0.369672, 0.000000},
{-0.908173, 0.376178, -0.029445},
{-0.939585, 0.389189, -0.029445},
{-1.014132, 0.201723, 0.000000},
{-0.997459, 0.198407, 0.029445},
{-0.964112, 0.191774, 0.029445},
{-0.947439, 0.188457, 0.000000},
{-0.964112, 0.191774, -0.029445},
{-0.997459, 0.198407, -0.029445},
{-1.034000, 0.000000, 0.000000},
{-1.017000, 0.000000, 0.029445},
{-0.983000, 0.000000, 0.029445},
{-0.966000, 0.000000, 0.000000},
{-0.983000, 0.000000, -0.029445},
{-1.017000, 0.000000, -0.029445},
{-1.014132, -0.201723, 0.000000},
{-0.997459, -0.198407, 0.029445},
{-0.964112, -0.191774, 0.029445},
{-0.947439, -0.188457, 0.000000},
{-0.964112, -0.191774, -0.029445},
{-0.997459, -0.198407, -0.029445},
{-0.955292, -0.395694, 0.000000},
{-0.939586, -0.389189, 0.029445},
{-0.908174, -0.376177, 0.029445},
{-0.892468, -0.369672, 0.000000},
{-0.908174, -0.376177, -0.029445},
{-0.939586, -0.389189, -0.029445},
{-0.859740, -0.574460, 0.000000},
{-0.845604, -0.565015, 0.029445},
{-0.817335, -0.546126, 0.029445},
{-0.803200, -0.536681, 0.000000},
{-0.817335, -0.546126, -0.029445},
{-0.845604, -0.565015, -0.029445},
{-0.731149, -0.731148, 0.000000},
{-0.719128, -0.719127, 0.029445},
{-0.695086, -0.695086, 0.029445},
{-0.683065, -0.683065, 0.000000},
{-0.695086, -0.695086, -0.029445},
{-0.719128, -0.719127, -0.029445},
{-0.574460, -0.859739, 0.000000},
{-0.565015, -0.845604, 0.029445},
{-0.546126, -0.817334, 0.029445},
{-0.536681, -0.803199, 0.000000},
{-0.546126, -0.817334, -0.029445},
{-0.565015, -0.845604, -0.029445},
{-0.395695, -0.955291, 0.000000},
{-0.389189, -0.939585, 0.029445},
{-0.376178, -0.908174, 0.029445},
{-0.369672, -0.892468, 0.000000},
{-0.376178, -0.908174, -0.029445},
{-0.389189, -0.939585, -0.029445},
{-0.201724, -1.014132, 0.000000},
{-0.198407, -0.997459, 0.029445},
{-0.191774, -0.964112, 0.029445},
{-0.188458, -0.947438, 0.000000},
{-0.191774, -0.964112, -0.029445},
{-0.198407, -0.997459, -0.029445},
{0.000000, -1.034000, 0.000000},
{0.000000, -1.017000, 0.029445},
{0.000000, -0.983000, 0.029445},
{0.000000, -0.966000, 0.000000},
{0.000000, -0.983000, -0.029445},
{0.000000, -1.017000, -0.029445},
{0.201723, -1.014132, 0.000000},
{0.198407, -0.997459, 0.029445},
{0.191773, -0.964112, 0.029445},
{0.188457, -0.947439, 0.000000},
{0.191773, -0.964112, -0.029445},
{0.198407, -0.997459, -0.029445},
{0.395695, -0.955291, 0.000000},
{0.389189, -0.939585, 0.029445},
{0.376178, -0.908173, 0.029445},
{0.369672, -0.892467, 0.000000},
{0.376178, -0.908173, -0.029445},
{0.389189, -0.939585, -0.029445},
{0.574460, -0.859740, 0.000000},
{0.565015, -0.845605, 0.029445},
{0.546125, -0.817335, 0.029445},
{0.536681, -0.803200, 0.000000},
{0.546125, -0.817335, -0.029445},
{0.565015, -0.845605, -0.029445},
{0.731148, -0.731149, 0.000000},
{0.719127, -0.719128, 0.029445},
{0.695086, -0.695086, 0.029445},
{0.683065, -0.683066, 0.000000},
{0.695086, -0.695086, -0.029445},
{0.719127, -0.719128, -0.029445},
{0.859740, -0.574460, 0.000000},
{0.845605, -0.565015, 0.029445},
{0.817335, -0.546126, 0.029445},
{0.803200, -0.536681, 0.000000},
{0.817335, -0.546126, -0.029445},
{0.845605, -0.565015, -0.029445},
{0.955291, -0.395695, 0.000000},
{0.939585, -0.389189, 0.029445},
{0.908173, -0.376178, 0.029445},
{0.892467, -0.369673, 0.000000},
{0.908173, -0.376178, -0.029445},
{0.939585, -0.389189, -0.029445},
{1.014132, -0.201723, 0.000000},
{0.997459, -0.198407, 0.029445},
{0.964112, -0.191774, 0.029445},
{0.947439, -0.188457, 0.000000},
{0.964112, -0.191774, -0.029445},
{0.997459, -0.198407, -0.029445},
};
float _WIDGET_normals_dial[][3] = {
{1.000000, 0.000000, 0.000000},
{0.522691, 0.000000, 0.852504},
{-0.475845, 0.000000, 0.879513},
{-1.000000, 0.000000, 0.000000},
{-0.475845, 0.000000, -0.879513},
{0.522691, 0.000000, -0.852504},
{0.980773, 0.195074, 0.000000},
{0.512650, 0.101962, 0.852504},
{-0.466689, -0.092807, 0.879513},
{-0.980773, -0.195074, 0.000000},
{-0.466689, -0.092807, -0.879513},
{0.512650, 0.101962, -0.852504},
{0.923856, 0.382672, 0.000000},
{0.482894, 0.200018, 0.852504},
{-0.439619, -0.182073, 0.879513},
{-0.923856, -0.382672, 0.000000},
{-0.439619, -0.182073, -0.879513},
{0.482894, 0.200018, -0.852504},
{0.831446, 0.555559, 0.000000},
{0.434614, 0.290384, 0.852504},
{-0.395642, -0.264351, 0.879513},
{-0.831446, -0.555559, 0.000000},
{-0.395642, -0.264351, -0.879513},
{0.434614, 0.290384, -0.852504},
{0.707083, 0.707083, 0.000000},
{0.369610, 0.369610, 0.852504},
{-0.336467, -0.336467, 0.879513},
{-0.707083, -0.707083, 0.000000},
{-0.336467, -0.336467, -0.879513},
{0.369610, 0.369610, -0.852504},
{0.555559, 0.831446, 0.000000},
{0.290384, 0.434614, 0.852504},
{-0.264351, -0.395642, 0.879513},
{-0.555559, -0.831446, 0.000000},
{-0.264351, -0.395642, -0.879513},
{0.290384, 0.434614, -0.852504},
{0.382672, 0.923856, 0.000000},
{0.200018, 0.482894, 0.852504},
{-0.182073, -0.439619, 0.879513},
{-0.382672, -0.923856, 0.000000},
{-0.182073, -0.439619, -0.879513},
{0.200018, 0.482894, -0.852504},
{0.195074, 0.980773, 0.000000},
{0.101962, 0.512650, 0.852504},
{-0.092807, -0.466689, 0.879513},
{-0.195074, -0.980773, 0.000000},
{-0.092807, -0.466689, -0.879513},
{0.101962, 0.512650, -0.852504},
{0.000000, 1.000000, 0.000000},
{0.000000, 0.522691, 0.852504},
{0.000000, -0.475845, 0.879513},
{0.000000, -1.000000, 0.000000},
{0.000000, -0.475845, -0.879513},
{0.000000, 0.522691, -0.852504},
{-0.195074, 0.980773, 0.000000},
{-0.101962, 0.512650, 0.852504},
{0.092807, -0.466689, 0.879513},
{0.195074, -0.980773, 0.000000},
{0.092807, -0.466689, -0.879513},
{-0.101962, 0.512650, -0.852504},
{-0.382672, 0.923856, 0.000000},
{-0.200018, 0.482894, 0.852504},
{0.182073, -0.439619, 0.879513},
{0.382672, -0.923856, 0.000000},
{0.182073, -0.439619, -0.879513},
{-0.200018, 0.482894, -0.852504},
{-0.555559, 0.831446, 0.000000},
{-0.290384, 0.434614, 0.852504},
{0.264351, -0.395642, 0.879513},
{0.555559, -0.831446, 0.000000},
{0.264351, -0.395642, -0.879513},
{-0.290384, 0.434614, -0.852504},
{-0.707083, 0.707083, 0.000000},
{-0.369610, 0.369610, 0.852504},
{0.336467, -0.336467, 0.879513},
{0.707083, -0.707083, 0.000000},
{0.336467, -0.336467, -0.879513},
{-0.369610, 0.369610, -0.852504},
{-0.831446, 0.555559, 0.000000},
{-0.434614, 0.290384, 0.852504},
{0.395642, -0.264351, 0.879513},
{0.831446, -0.555559, 0.000000},
{0.395642, -0.264351, -0.879513},
{-0.434614, 0.290384, -0.852504},
{-0.923856, 0.382672, 0.000000},
{-0.482894, 0.200018, 0.852504},
{0.439619, -0.182073, 0.879513},
{0.923856, -0.382672, 0.000000},
{0.439619, -0.182073, -0.879513},
{-0.482894, 0.200018, -0.852504},
{-0.980773, 0.195074, 0.000000},
{-0.512650, 0.101962, 0.852504},
{0.466689, -0.092807, 0.879513},
{0.980773, -0.195074, 0.000000},
{0.466689, -0.092807, -0.879513},
{-0.512650, 0.101962, -0.852504},
{-1.000000, 0.000000, 0.000000},
{-0.522691, 0.000000, 0.852504},
{0.475845, 0.000000, 0.879513},
{1.000000, 0.000000, 0.000000},
{0.475845, 0.000000, -0.879513},
{-0.522691, 0.000000, -0.852504},
{-0.980773, -0.195074, 0.000000},
{-0.512650, -0.101962, 0.852504},
{0.466689, 0.092807, 0.879513},
{0.980773, 0.195074, 0.000000},
{0.466689, 0.092807, -0.879513},
{-0.512650, -0.101962, -0.852504},
{-0.923856, -0.382672, 0.000000},
{-0.482894, -0.200018, 0.852504},
{0.439619, 0.182073, 0.879513},
{0.923856, 0.382672, 0.000000},
{0.439619, 0.182073, -0.879513},
{-0.482894, -0.200018, -0.852504},
{-0.831446, -0.555559, 0.000000},
{-0.434614, -0.290384, 0.852504},
{0.395642, 0.264351, 0.879513},
{0.831446, 0.555559, 0.000000},
{0.395642, 0.264351, -0.879513},
{-0.434614, -0.290384, -0.852504},
{-0.707083, -0.707083, 0.000000},
{-0.369610, -0.369610, 0.852504},
{0.336467, 0.336467, 0.879513},
{0.707083, 0.707083, 0.000000},
{0.336467, 0.336467, -0.879513},
{-0.369610, -0.369610, -0.852504},
{-0.555559, -0.831446, 0.000000},
{-0.290384, -0.434614, 0.852504},
{0.264351, 0.395642, 0.879513},
{0.555559, 0.831446, 0.000000},
{0.264351, 0.395642, -0.879513},
{-0.290384, -0.434614, -0.852504},
{-0.382672, -0.923856, 0.000000},
{-0.200018, -0.482894, 0.852504},
{0.182073, 0.439619, 0.879513},
{0.382672, 0.923856, 0.000000},
{0.182073, 0.439619, -0.879513},
{-0.200018, -0.482894, -0.852504},
{-0.195074, -0.980773, 0.000000},
{-0.101962, -0.512650, 0.852504},
{0.092807, 0.466689, 0.879513},
{0.195074, 0.980773, 0.000000},
{0.092807, 0.466689, -0.879513},
{-0.101962, -0.512650, -0.852504},
{0.000000, -1.000000, 0.000000},
{0.000000, -0.522691, 0.852504},
{0.000000, 0.475845, 0.879513},
{0.000000, 1.000000, 0.000000},
{0.000000, 0.475845, -0.879513},
{0.000000, -0.522691, -0.852504},
{0.195074, -0.980773, 0.000000},
{0.101962, -0.512650, 0.852504},
{-0.092807, 0.466689, 0.879513},
{-0.195074, 0.980773, 0.000000},
{-0.092807, 0.466689, -0.879513},
{0.101962, -0.512650, -0.852504},
{0.382672, -0.923856, 0.000000},
{0.200018, -0.482894, 0.852504},
{-0.182073, 0.439619, 0.879513},
{-0.382672, 0.923856, 0.000000},
{-0.182073, 0.439619, -0.879513},
{0.200018, -0.482894, -0.852504},
{0.555559, -0.831446, 0.000000},
{0.290384, -0.434614, 0.852504},
{-0.264351, 0.395642, 0.879513},
{-0.555559, 0.831446, 0.000000},
{-0.264351, 0.395642, -0.879513},
{0.290384, -0.434614, -0.852504},
{0.707083, -0.707083, 0.000000},
{0.369610, -0.369610, 0.852504},
{-0.336467, 0.336467, 0.879513},
{-0.707083, 0.707083, 0.000000},
{-0.336467, 0.336467, -0.879513},
{0.369610, -0.369610, -0.852504},
{0.831446, -0.555559, 0.000000},
{0.434614, -0.290384, 0.852504},
{-0.395642, 0.264351, 0.879513},
{-0.831446, 0.555559, 0.000000},
{-0.395642, 0.264351, -0.879513},
{0.434614, -0.290384, -0.852504},
{0.923856, -0.382672, 0.000000},
{0.482894, -0.200018, 0.852504},
{-0.439619, 0.182073, 0.879513},
{-0.923856, 0.382672, 0.000000},
{-0.439619, 0.182073, -0.879513},
{0.482894, -0.200018, -0.852504},
{0.980773, -0.195074, 0.000000},
{0.512650, -0.101962, 0.852504},
{-0.466689, 0.092807, 0.879513},
{-0.980773, 0.195074, 0.000000},
{-0.466689, 0.092807, -0.879513},
{0.512650, -0.101962, -0.852504},
};
unsigned short _WIDGET_indices_dial[] = {
6, 7, 1,
7, 8, 2,
8, 9, 3,
9, 10, 4,
10, 11, 5,
5, 11, 6,
12, 13, 7,
13, 14, 8,
14, 15, 9,
15, 16, 10,
16, 17, 11,
11, 17, 12,
18, 19, 13,
13, 19, 20,
20, 21, 15,
15, 21, 22,
22, 23, 17,
17, 23, 18,
24, 25, 19,
19, 25, 26,
26, 27, 21,
21, 27, 28,
28, 29, 23,
23, 29, 24,
30, 31, 25,
25, 31, 32,
26, 32, 33,
27, 33, 34,
34, 35, 29,
29, 35, 30,
36, 37, 31,
31, 37, 38,
38, 39, 33,
39, 40, 34,
40, 41, 35,
35, 41, 36,
36, 42, 43,
43, 44, 38,
44, 45, 39,
45, 46, 40,
46, 47, 41,
47, 42, 36,
48, 49, 43,
49, 50, 44,
50, 51, 45,
51, 52, 46,
52, 53, 47,
47, 53, 48,
54, 55, 49,
49, 55, 56,
50, 56, 57,
57, 58, 52,
58, 59, 53,
53, 59, 54,
60, 61, 55,
55, 61, 62,
56, 62, 63,
63, 64, 58,
64, 65, 59,
59, 65, 60,
66, 67, 61,
61, 67, 68,
68, 69, 63,
69, 70, 64,
70, 71, 65,
71, 66, 60,
72, 73, 67,
73, 74, 68,
68, 74, 75,
75, 76, 70,
76, 77, 71,
71, 77, 72,
78, 79, 73,
79, 80, 74,
74, 80, 81,
81, 82, 76,
82, 83, 77,
83, 78, 72,
78, 84, 85,
85, 86, 80,
80, 86, 87,
87, 88, 82,
82, 88, 89,
89, 84, 78,
90, 91, 85,
91, 92, 86,
86, 92, 93,
93, 94, 88,
88, 94, 95,
95, 90, 84,
96, 97, 91,
97, 98, 92,
98, 99, 93,
99, 100, 94,
100, 101, 95,
101, 96, 90,
102, 103, 97,
103, 104, 98,
104, 105, 99,
99, 105, 106,
106, 107, 101,
101, 107, 102,
108, 109, 103,
103, 109, 110,
110, 111, 105,
105, 111, 112,
112, 113, 107,
107, 113, 108,
114, 115, 109,
115, 116, 110,
116, 117, 111,
111, 117, 118,
112, 118, 119,
113, 119, 114,
114, 120, 121,
121, 122, 116,
122, 123, 117,
117, 123, 124,
124, 125, 119,
125, 120, 114,
126, 127, 121,
121, 127, 128,
128, 129, 123,
123, 129, 130,
130, 131, 125,
125, 131, 126,
132, 133, 127,
133, 134, 128,
128, 134, 135,
135, 136, 130,
136, 137, 131,
131, 137, 132,
132, 138, 139,
133, 139, 140,
134, 140, 141,
141, 142, 136,
142, 143, 137,
143, 138, 132,
138, 144, 145,
139, 145, 146,
146, 147, 141,
141, 147, 148,
148, 149, 143,
149, 144, 138,
144, 150, 151,
151, 152, 146,
146, 152, 153,
153, 154, 148,
154, 155, 149,
155, 150, 144,
156, 157, 151,
151, 157, 158,
158, 159, 153,
159, 160, 154,
160, 161, 155,
155, 161, 156,
156, 162, 163,
163, 164, 158,
158, 164, 165,
165, 166, 160,
160, 166, 167,
167, 162, 156,
162, 168, 169,
169, 170, 164,
164, 170, 171,
165, 171, 172,
166, 172, 173,
173, 168, 162,
174, 175, 169,
175, 176, 170,
170, 176, 177,
177, 178, 172,
172, 178, 179,
173, 179, 174,
174, 180, 181,
181, 182, 176,
176, 182, 183,
183, 184, 178,
178, 184, 185,
179, 185, 180,
186, 187, 181,
187, 188, 182,
188, 189, 183,
183, 189, 190,
190, 191, 185,
191, 186, 180,
0, 1, 187,
1, 2, 188,
2, 3, 189,
3, 4, 190,
190, 4, 5,
191, 5, 0,
0, 6, 1,
1, 7, 2,
2, 8, 3,
3, 9, 4,
4, 10, 5,
0, 5, 6,
6, 12, 7,
7, 13, 8,
8, 14, 9,
9, 15, 10,
10, 16, 11,
6, 11, 12,
12, 18, 13,
14, 13, 20,
14, 20, 15,
16, 15, 22,
16, 22, 17,
12, 17, 18,
18, 24, 19,
20, 19, 26,
20, 26, 21,
22, 21, 28,
22, 28, 23,
18, 23, 24,
24, 30, 25,
26, 25, 32,
27, 26, 33,
28, 27, 34,
28, 34, 29,
24, 29, 30,
30, 36, 31,
32, 31, 38,
32, 38, 33,
33, 39, 34,
34, 40, 35,
30, 35, 36,
37, 36, 43,
37, 43, 38,
38, 44, 39,
39, 45, 40,
40, 46, 41,
41, 47, 36,
42, 48, 43,
43, 49, 44,
44, 50, 45,
45, 51, 46,
46, 52, 47,
42, 47, 48,
48, 54, 49,
50, 49, 56,
51, 50, 57,
51, 57, 52,
52, 58, 53,
48, 53, 54,
54, 60, 55,
56, 55, 62,
57, 56, 63,
57, 63, 58,
58, 64, 59,
54, 59, 60,
60, 66, 61,
62, 61, 68,
62, 68, 63,
63, 69, 64,
64, 70, 65,
65, 71, 60,
66, 72, 67,
67, 73, 68,
69, 68, 75,
69, 75, 70,
70, 76, 71,
66, 71, 72,
72, 78, 73,
73, 79, 74,
75, 74, 81,
75, 81, 76,
76, 82, 77,
77, 83, 72,
79, 78, 85,
79, 85, 80,
81, 80, 87,
81, 87, 82,
83, 82, 89,
83, 89, 78,
84, 90, 85,
85, 91, 86,
87, 86, 93,
87, 93, 88,
89, 88, 95,
89, 95, 84,
90, 96, 91,
91, 97, 92,
92, 98, 93,
93, 99, 94,
94, 100, 95,
95, 101, 90,
96, 102, 97,
97, 103, 98,
98, 104, 99,
100, 99, 106,
100, 106, 101,
96, 101, 102,
102, 108, 103,
104, 103, 110,
104, 110, 105,
106, 105, 112,
106, 112, 107,
102, 107, 108,
108, 114, 109,
109, 115, 110,
110, 116, 111,
112, 111, 118,
113, 112, 119,
108, 113, 114,
115, 114, 121,
115, 121, 116,
116, 122, 117,
118, 117, 124,
118, 124, 119,
119, 125, 114,
120, 126, 121,
122, 121, 128,
122, 128, 123,
124, 123, 130,
124, 130, 125,
120, 125, 126,
126, 132, 127,
127, 133, 128,
129, 128, 135,
129, 135, 130,
130, 136, 131,
126, 131, 132,
133, 132, 139,
134, 133, 140,
135, 134, 141,
135, 141, 136,
136, 142, 137,
137, 143, 132,
139, 138, 145,
140, 139, 146,
140, 146, 141,
142, 141, 148,
142, 148, 143,
143, 149, 138,
145, 144, 151,
145, 151, 146,
147, 146, 153,
147, 153, 148,
148, 154, 149,
149, 155, 144,
150, 156, 151,
152, 151, 158,
152, 158, 153,
153, 159, 154,
154, 160, 155,
150, 155, 156,
157, 156, 163,
157, 163, 158,
159, 158, 165,
159, 165, 160,
161, 160, 167,
161, 167, 156,
163, 162, 169,
163, 169, 164,
165, 164, 171,
166, 165, 172,
167, 166, 173,
167, 173, 162,
168, 174, 169,
169, 175, 170,
171, 170, 177,
171, 177, 172,
173, 172, 179,
168, 173, 174,
175, 174, 181,
175, 181, 176,
177, 176, 183,
177, 183, 178,
179, 178, 185,
174, 179, 180,
180, 186, 181,
181, 187, 182,
182, 188, 183,
184, 183, 190,
184, 190, 185,
185, 191, 180,
186, 0, 187,
187, 1, 188,
188, 2, 189,
189, 3, 190,
191, 190, 5,
186, 191, 0,
};

View File

@@ -0,0 +1,248 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/primitive_widget.c
* \ingroup wm
*
* \name Primitive Widget
*
* 3D Widget
*
* \brief Widget with primitive drawing type (plane, cube, etc.).
* Currently only plane primitive supported without own handling, use with operator only.
*/
#include "BIF_gl.h"
#include "BKE_context.h"
#include "BLI_math.h"
#include "DNA_view3d_types.h"
#include "DNA_widget_types.h"
#include "GPU_select.h"
#include "MEM_guardedalloc.h"
#include "WM_api.h"
#include "WM_types.h"
/* own includes */
#include "WM_widget_types.h"
#include "WM_widget_library.h"
#include "wm_widget_wmapi.h"
#include "wm_widget_intern.h"
#include "widget_library_intern.h"
/* PrimitiveWidget->flag */
#define PRIM_UP_VECTOR_SET 1
typedef struct PrimitiveWidget {
wmWidget widget;
float direction[3];
float up[3];
int style;
int flag;
} PrimitiveWidget;
static float verts_plane[4][3] = {
{-1, -1, 0},
{ 1, -1, 0},
{ 1, 1, 0},
{-1, 1, 0},
};
/* -------------------------------------------------------------------- */
static void widget_primitive_draw_geom(const float col_inner[4], const float col_outer[4], const int style)
{
float (*verts)[3];
float vert_count;
if (style == WIDGET_PRIMITIVE_STYLE_PLANE) {
verts = verts_plane;
vert_count = ARRAY_SIZE(verts_plane);
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, verts);
glColor4fv(col_inner);
glDrawArrays(GL_QUADS, 0, vert_count);
glColor4fv(col_outer);
glDrawArrays(GL_LINE_LOOP, 0, vert_count);
glDisableClientState(GL_VERTEX_ARRAY);
}
static void widget_primitive_draw_intern(PrimitiveWidget *prim, const bool UNUSED(select), const bool highlight)
{
float col_inner[4], col_outer[4];
float rot[3][3];
float mat[4][4];
if (prim->flag & PRIM_UP_VECTOR_SET) {
copy_v3_v3(rot[2], prim->direction);
copy_v3_v3(rot[1], prim->up);
cross_v3_v3v3(rot[0], prim->up, prim->direction);
}
else {
const float up[3] = {0.0f, 0.0f, 1.0f};
rotation_between_vecs_to_mat3(rot, up, prim->direction);
}
copy_m4_m3(mat, rot);
copy_v3_v3(mat[3], prim->widget.origin);
mul_mat3_m4_fl(mat, prim->widget.scale);
glPushMatrix();
glMultMatrixf(mat);
if (highlight && (prim->widget.flag & WM_WIDGET_DRAW_HOVER) == 0) {
copy_v4_v4(col_inner, prim->widget.col_hi);
copy_v4_v4(col_outer, prim->widget.col_hi);
}
else {
copy_v4_v4(col_inner, prim->widget.col);
copy_v4_v4(col_outer, prim->widget.col);
}
col_inner[3] *= 0.5f;
glEnable(GL_BLEND);
glTranslate3fv(prim->widget.offset);
widget_primitive_draw_geom(col_inner, col_outer, prim->style);
glDisable(GL_BLEND);
glPopMatrix();
if (prim->widget.interaction_data) {
WidgetInteraction *inter = prim->widget.interaction_data;
copy_v4_fl(col_inner, 0.5f);
copy_v3_fl(col_outer, 0.5f);
col_outer[3] = 0.8f;
copy_m4_m3(mat, rot);
copy_v3_v3(mat[3], inter->init_origin);
mul_mat3_m4_fl(mat, inter->init_scale);
glPushMatrix();
glMultMatrixf(mat);
glEnable(GL_BLEND);
glTranslate3fv(prim->widget.offset);
widget_primitive_draw_geom(col_inner, col_outer, prim->style);
glDisable(GL_BLEND);
glPopMatrix();
}
}
static void widget_primitive_render_3d_intersect(const bContext *UNUSED(C), wmWidget *widget, int selectionbase)
{
GPU_select_load_id(selectionbase);
widget_primitive_draw_intern((PrimitiveWidget *)widget, true, false);
}
static void widget_primitive_draw(const bContext *UNUSED(C), wmWidget *widget)
{
widget_primitive_draw_intern((PrimitiveWidget *)widget, false, (widget->flag & WM_WIDGET_HIGHLIGHT));
}
static int widget_primitive_invoke(bContext *UNUSED(C), const wmEvent *UNUSED(event), wmWidget *widget)
{
WidgetInteraction *inter = MEM_callocN(sizeof(WidgetInteraction), __func__);
copy_v3_v3(inter->init_origin, widget->origin);
inter->init_scale = widget->scale;
widget->interaction_data = inter;
return OPERATOR_RUNNING_MODAL;
}
/* -------------------------------------------------------------------- */
/** \name Primitive Widget API
*
* \{ */
wmWidget *WIDGET_primitive_new(wmWidgetGroup *wgroup, const char *name, const int style)
{
PrimitiveWidget *prim = MEM_callocN(sizeof(PrimitiveWidget), name);
const float dir_default[3] = {0.0f, 0.0f, 1.0f};
prim->widget.draw = widget_primitive_draw;
prim->widget.invoke = widget_primitive_invoke;
prim->widget.intersect = NULL;
prim->widget.render_3d_intersection = widget_primitive_render_3d_intersect;
prim->widget.flag |= (WM_WIDGET_DRAW_ACTIVE | WM_WIDGET_SCALE_3D);
prim->style = style;
/* defaults */
copy_v3_v3(prim->direction, dir_default);
wm_widget_register(wgroup, &prim->widget, name);
return (wmWidget *)prim;
}
/**
* Define direction the primitive will point towards
*/
void WIDGET_primitive_set_direction(wmWidget *widget, const float direction[3])
{
PrimitiveWidget *prim = (PrimitiveWidget *)widget;
copy_v3_v3(prim->direction, direction);
normalize_v3(prim->direction);
}
/**
* Define up-direction of the primitive widget
*/
void WIDGET_primitive_set_up_vector(wmWidget *widget, const float direction[3])
{
PrimitiveWidget *prim = (PrimitiveWidget *)widget;
if (direction) {
copy_v3_v3(prim->up, direction);
normalize_v3(prim->up);
prim->flag |= PRIM_UP_VECTOR_SET;
}
else {
prim->flag &= ~PRIM_UP_VECTOR_SET;
}
}
/** \} */ // Primitive Widget API
/* -------------------------------------------------------------------- */
void fix_linking_widget_primitive(void)
{
(void)0;
}

View File

@@ -0,0 +1,67 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/widget_geometry.h
* \ingroup wm
*
* \name Widget Geometry
*
* \brief Prototypes for arrays defining the widget geometry. The actual definitions can be found in files usually
* called geom_xxx_widget.c
*/
#ifndef __WIDGET_GEOMETRY_H__
#define __WIDGET_GEOMETRY_H__
/* arrow widget */
extern int _WIDGET_nverts_arrow;
extern int _WIDGET_ntris_arrow;
extern float _WIDGET_verts_arrow[][3];
extern float _WIDGET_normals_arrow[][3];
extern unsigned short _WIDGET_indices_arrow[];
/* cube widget */
extern int _WIDGET_nverts_cube;
extern int _WIDGET_ntris_cube;
extern float _WIDGET_verts_cube[][3];
extern float _WIDGET_normals_cube[][3];
extern unsigned short _WIDGET_indices_cube[];
/* dial widget */
extern int _WIDGET_nverts_dial;
extern int _WIDGET_ntris_dial;
extern float _WIDGET_verts_dial[][3];
extern float _WIDGET_normals_dial[][3];
extern unsigned short _WIDGET_indices_dial[];
#endif /* __WIDGET_GEOMETRY_H__ */

View File

@@ -0,0 +1,93 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/widget_library_intern.h
* \ingroup wm
*/
#ifndef __WIDGET_LIBRARY_INTERN_H__
#define __WIDGET_LIBRARY_INTERN_H__
/* distance around which widgets respond to input (and get highlighted) */
#define WIDGET_HOTSPOT 14.0f /* TODO use everywhere */
/**
* Data for common interactions. Used in widget_library_utils.c functions.
*/
typedef struct WidgetCommonData {
int flag;
float range_fac; /* factor for arrow min/max distance */
float offset;
/* property range for constrained widgets */
float range;
/* min/max value for constrained widgets */
float min, max;
} WidgetCommonData;
typedef struct WidgetInteraction {
float init_value; /* initial property value */
float init_origin[3];
float init_mval[2];
float init_offset;
float init_scale;
/* offset of last handling step */
float prev_offset;
/* Total offset added by precision tweaking.
* Needed to allow toggling precision on/off without causing jumps */
float precision_offset;
} WidgetInteraction;
/* WidgetCommonData->flag */
enum {
WIDGET_CUSTOM_RANGE_SET = (1 << 0),
};
float widget_offset_from_value(
WidgetCommonData *data, const float value,
const bool constrained, const bool inverted);
float widget_value_from_offset(
WidgetCommonData *data, WidgetInteraction *inter, const float offset,
const bool constrained, const bool inverted, const bool use_precision);
void widget_property_data_update(
wmWidget *widget, WidgetCommonData *data, const int slot,
const bool constrained, const bool inverted);
void widget_property_value_set(bContext *C, const wmWidget *widget, const int slot, const float value);
float widget_property_value_get(const wmWidget *widget, const int slot);
void widget_property_value_reset(bContext *C, const wmWidget *widget, WidgetInteraction *inter, const int slot);
/* -------------------------------------------------------------------- */
float *widget_color_get(wmWidget *widget, const bool highlight);
#endif /* __WIDGET_LIBRARY_INTERN_H__ */

View File

@@ -0,0 +1,157 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2015 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/widget_library/widget_library_utils.c
* \ingroup wm
*
* \name Widget Library Utilities
*
* \brief This file contains functions for common behaviors of widgets.
*/
#include "BKE_context.h"
#include "RNA_access.h"
#include "WM_api.h"
/* own includes */
#include "WM_widget_types.h"
#include "wm_widget_wmapi.h"
#include "widget_library_intern.h"
/* factor for precision tweaking */
#define WIDGET_PRECISION_FAC 0.05f
BLI_INLINE float widget_offset_from_value_constr(
const float range_fac, const float min, const float range, const float value,
const bool inverted)
{
return inverted ? (range_fac * (min + range - value) / range) : (range_fac * (value / range));
}
BLI_INLINE float widget_value_from_offset_constr(
const float range_fac, const float min, const float range, const float value,
const bool inverted)
{
return inverted ? (min + range - (value * range / range_fac)) : (value * range / range_fac);
}
float widget_offset_from_value(WidgetCommonData *data, const float value, const bool constrained, const bool inverted)
{
if (constrained)
return widget_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
return value;
}
float widget_value_from_offset(
WidgetCommonData *data, WidgetInteraction *inter, const float offset,
const bool constrained, const bool inverted, const bool use_precision)
{
const float max = data->min + data->range;
if (use_precision) {
/* add delta offset of this step to total precision_offset */
inter->precision_offset += offset - inter->prev_offset;
}
inter->prev_offset = offset;
float ofs_new = inter->init_offset + offset - inter->precision_offset * (1.0f - WIDGET_PRECISION_FAC);
float value;
if (constrained) {
value = widget_value_from_offset_constr(data->range_fac, data->min, data->range, ofs_new, inverted);
}
else {
value = ofs_new;
}
/* clamp to custom range */
if (data->flag & WIDGET_CUSTOM_RANGE_SET) {
CLAMP(value, data->min, max);
}
return value;
}
void widget_property_data_update(
wmWidget *widget, WidgetCommonData *data, const int slot,
const bool constrained, const bool inverted)
{
if (!widget->props[slot]) {
data->offset = 0.0f;
return;
}
PointerRNA ptr = widget->ptr[slot];
PropertyRNA *prop = widget->props[slot];
float value = widget_property_value_get(widget, slot);
if (constrained) {
if ((data->flag & WIDGET_CUSTOM_RANGE_SET) == 0) {
float step, precision;
float min, max;
RNA_property_float_ui_range(&ptr, prop, &min, &max, &step, &precision);
data->range = max - min;
data->min = min;
}
data->offset = widget_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
}
else {
data->offset = value;
}
}
void widget_property_value_set(bContext *C, const wmWidget *widget, const int slot, const float value)
{
PointerRNA ptr = widget->ptr[slot];
PropertyRNA *prop = widget->props[slot];
/* reset property */
RNA_property_float_set(&ptr, prop, value);
RNA_property_update(C, &ptr, prop);
}
float widget_property_value_get(const wmWidget *widget, const int slot)
{
BLI_assert(RNA_property_type(widget->props[slot]) == PROP_FLOAT);
return RNA_property_float_get(&widget->ptr[slot], widget->props[slot]);
}
void widget_property_value_reset(bContext *C, const wmWidget *widget, WidgetInteraction *inter, const int slot)
{
widget_property_value_set(C, widget, slot, inter->init_value);
}
/* -------------------------------------------------------------------- */
/* TODO use everywhere */
float *widget_color_get(wmWidget *widget, const bool highlight)
{
return (highlight && !(widget->flag & WM_WIDGET_DRAW_HOVER)) ? widget->col_hi : widget->col;
}

View File

@@ -0,0 +1,416 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2014 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/wm_widget.c
* \ingroup wm
*/
#include "BKE_context.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "GL/glew.h"
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
/* own includes */
#include "wm_widget_wmapi.h"
#include "wm_widget_intern.h"
/**
* Main draw call for WidgetDrawInfo data
*/
void widget_draw_intern(WidgetDrawInfo *info, const bool select)
{
GLuint buf[3];
const bool use_lighting = !select && ((U.widget_flag & V3D_SHADED_WIDGETS) != 0);
if (use_lighting)
glGenBuffers(3, buf);
else
glGenBuffers(2, buf);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buf[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * info->nverts, info->verts, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, NULL);
if (use_lighting) {
glEnableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buf[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * info->nverts, info->normals, GL_STATIC_DRAW);
glNormalPointer(GL_FLOAT, 0, NULL);
glShadeModel(GL_SMOOTH);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * (3 * info->ntris), info->indices, GL_STATIC_DRAW);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDrawElements(GL_TRIANGLES, info->ntris * 3, GL_UNSIGNED_SHORT, NULL);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
if (use_lighting) {
glDisableClientState(GL_NORMAL_ARRAY);
glShadeModel(GL_FLAT);
glDeleteBuffers(3, buf);
}
else {
glDeleteBuffers(2, buf);
}
}
/* Still unused */
wmWidget *WM_widget_new(void (*draw)(const bContext *C, wmWidget *customdata),
void (*render_3d_intersection)(const bContext *C, wmWidget *customdata, int selectionbase),
int (*intersect)(bContext *C, const wmEvent *event, wmWidget *widget),
int (*handler)(bContext *C, const wmEvent *event, wmWidget *widget, const int flag))
{
wmWidget *widget = MEM_callocN(sizeof(wmWidget), "widget");
widget->draw = draw;
widget->handler = handler;
widget->intersect = intersect;
widget->render_3d_intersection = render_3d_intersection;
/* XXX */
fix_linking_widget_arrow();
fix_linking_widget_arrow2d();
fix_linking_widget_cage();
fix_linking_widget_dial();
fix_linking_widget_facemap();
fix_linking_widget_primitive();
return widget;
}
/**
* Assign an idname that is unique in \a wgroup to \a widget.
*
* \param rawname Name used as basis to define final unique idname.
*/
static void widget_unique_idname_set(wmWidgetGroup *wgroup, wmWidget *widget, const char *rawname)
{
if (wgroup->type->idname[0]) {
BLI_snprintf(widget->idname, sizeof(widget->idname), "%s_%s", wgroup->type->idname, rawname);
}
else {
BLI_strncpy(widget->idname, rawname, sizeof(widget->idname));
}
/* ensure name is unique, append '.001', '.002', etc if not */
BLI_uniquename(&wgroup->widgets, widget, "Widget", '.', offsetof(wmWidget, idname), sizeof(widget->idname));
}
/**
* Register \a widget.
*
* \param name name used to create a unique idname for \a widget in \a wgroup
*/
bool wm_widget_register(wmWidgetGroup *wgroup, wmWidget *widget, const char *name)
{
const float col_default[4] = {1.0f, 1.0f, 1.0f, 1.0f};
widget_unique_idname_set(wgroup, widget, name);
widget->user_scale = 1.0f;
widget->line_width = 1.0f;
/* defaults */
copy_v4_v4(widget->col, col_default);
copy_v4_v4(widget->col_hi, col_default);
/* create at least one property for interaction */
if (widget->max_prop == 0) {
widget->max_prop = 1;
}
widget->props = MEM_callocN(sizeof(PropertyRNA *) * widget->max_prop, "widget->props");
widget->ptr = MEM_callocN(sizeof(PointerRNA) * widget->max_prop, "widget->ptr");
widget->wgroup = wgroup;
BLI_addtail(&wgroup->widgets, widget);
return true;
}
/**
* Free \a widget and unlink from \a widgetlist.
* \a widgetlist is allowed to be NULL.
*/
void WM_widget_delete(ListBase *widgetlist, wmWidgetMap *wmap, wmWidget *widget, bContext *C)
{
if (widget->flag & WM_WIDGET_HIGHLIGHT) {
wm_widgetmap_set_highlighted_widget(wmap, C, NULL, 0);
}
if (widget->flag & WM_WIDGET_ACTIVE) {
wm_widgetmap_set_active_widget(wmap, C, NULL, NULL);
}
if (widget->flag & WM_WIDGET_SELECTED) {
wm_widget_deselect(wmap, widget);
}
if (widget->opptr.data) {
WM_operator_properties_free(&widget->opptr);
}
MEM_freeN(widget->props);
MEM_freeN(widget->ptr);
if (widgetlist)
BLI_remlink(widgetlist, widget);
MEM_freeN(widget);
}
/* -------------------------------------------------------------------- */
/** \name Widget Creation API
*
* API for defining data on widget creation.
*
* \{ */
void WM_widget_set_property(wmWidget *widget, const int slot, PointerRNA *ptr, const char *propname)
{
if (slot < 0 || slot >= widget->max_prop) {
fprintf(stderr, "invalid index %d when binding property for widget type %s\n", slot, widget->idname);
return;
}
/* if widget evokes an operator we cannot use it for property manipulation */
widget->opname = NULL;
widget->ptr[slot] = *ptr;
widget->props[slot] = RNA_struct_find_property(ptr, propname);
if (widget->prop_data_update)
widget->prop_data_update(widget, slot);
}
PointerRNA *WM_widget_set_operator(wmWidget *widget, const char *opname)
{
wmOperatorType *ot = WM_operatortype_find(opname, 0);
if (ot) {
widget->opname = opname;
if (widget->opptr.data) {
WM_operator_properties_free(&widget->opptr);
}
WM_operator_properties_create_ptr(&widget->opptr, ot);
return &widget->opptr;
}
else {
fprintf(stderr, "Error binding operator to widget: operator %s not found!\n", opname);
}
return NULL;
}
/**
* \brief Set widget select callback.
*
* Callback is called when widget gets selected/deselected.
*/
void WM_widget_set_func_select(wmWidget *widget, wmWidgetSelectFunc select)
{
widget->flag |= WM_WIDGET_SELECTABLE;
widget->select = select;
}
void WM_widget_set_origin(wmWidget *widget, const float origin[3])
{
copy_v3_v3(widget->origin, origin);
}
void WM_widget_set_offset(wmWidget *widget, const float offset[3])
{
copy_v3_v3(widget->offset, offset);
}
void WM_widget_set_flag(wmWidget *widget, const int flag, const bool enable)
{
if (enable) {
widget->flag |= flag;
}
else {
widget->flag &= ~flag;
}
}
void WM_widget_set_scale(wmWidget *widget, const float scale)
{
widget->user_scale = scale;
}
void WM_widget_set_line_width(wmWidget *widget, const float line_width)
{
widget->line_width = line_width;
}
/**
* Set widget rgba colors.
*
* \param col Normal state color.
* \param col_hi Highlighted state color.
*/
void WM_widget_set_colors(wmWidget *widget, const float col[4], const float col_hi[4])
{
copy_v4_v4(widget->col, col);
copy_v4_v4(widget->col_hi, col_hi);
}
/** \} */ // Widget Creation API
/* -------------------------------------------------------------------- */
/**
* Remove \a widget from selection.
* Reallocates memory for selected widgets so better not call for selecting multiple ones.
*
* \return if the selection has changed.
*/
bool wm_widget_deselect(wmWidgetMap *wmap, wmWidget *widget)
{
if (!wmap->wmap_context.selected_widgets)
return false;
wmWidget ***sel = &wmap->wmap_context.selected_widgets;
int *tot_selected = &wmap->wmap_context.tot_selected;
bool changed = false;
/* caller should check! */
BLI_assert(widget->flag & WM_WIDGET_SELECTED);
/* remove widget from selected_widgets array */
for (int i = 0; i < (*tot_selected); i++) {
if ((*sel)[i] == widget) {
for (int j = i; j < ((*tot_selected) - 1); j++) {
(*sel)[j] = (*sel)[j + 1];
}
changed = true;
break;
}
}
/* update array data */
if ((*tot_selected) <= 1) {
wm_widgetmap_selected_delete(wmap);
}
else {
*sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_selected));
(*tot_selected)--;
}
widget->flag &= ~WM_WIDGET_SELECTED;
return changed;
}
/**
* Add \a widget to selection.
* Reallocates memory for selected widgets so better not call for selecting multiple ones.
*
* \return if the selection has changed.
*/
bool wm_widget_select(bContext *C, wmWidgetMap *wmap, wmWidget *widget)
{
wmWidget ***sel = &wmap->wmap_context.selected_widgets;
int *tot_selected = &wmap->wmap_context.tot_selected;
if (!widget || (widget->flag & WM_WIDGET_SELECTED))
return false;
(*tot_selected)++;
*sel = MEM_reallocN(*sel, sizeof(wmWidget *) * (*tot_selected));
(*sel)[(*tot_selected) - 1] = widget;
widget->flag |= WM_WIDGET_SELECTED;
if (widget->select) {
widget->select(C, widget, SEL_SELECT);
}
wm_widgetmap_set_highlighted_widget(wmap, C, widget, widget->highlighted_part);
return true;
}
void wm_widget_calculate_scale(wmWidget *widget, const bContext *C)
{
const RegionView3D *rv3d = CTX_wm_region_view3d(C);
float scale = 1.0f;
if (widget->flag & WM_WIDGET_SCALE_3D) {
if (rv3d && (U.widget_flag & V3D_3D_WIDGETS) == 0) {
if (widget->get_final_position) {
float position[3];
widget->get_final_position(widget, position);
scale = ED_view3d_pixel_size(rv3d, position) * (float)U.widget_scale;
}
else {
scale = ED_view3d_pixel_size(rv3d, widget->origin) * (float)U.widget_scale;
}
}
else {
scale = U.widget_scale * 0.02f;
}
}
widget->scale = scale * widget->user_scale;
}
void wm_widget_update_prop_data(wmWidget *widget)
{
/* widget property might have been changed, so update widget */
if (widget->props && widget->prop_data_update) {
for (int i = 0; i < widget->max_prop; i++) {
if (widget->props[i]) {
widget->prop_data_update(widget, i);
}
}
}
}

View File

@@ -0,0 +1,116 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/wm_widget_intern.h
* \ingroup wm
*/
#ifndef __WM_WIDGET_INTERN_H__
#define __WM_WIDGET_INTERN_H__
struct wmKeyConfig;
struct wmWidget;
struct wmWidgetMap;
/* -------------------------------------------------------------------- */
/* wmWidget */
/**
* \brief Widget tweak flag.
* Bitflag passed to widget while tweaking.
*/
enum {
/* drag with extra precision (shift)
* NOTE: Widgets are responsible for handling this (widget->handler callback)! */
WM_WIDGET_TWEAK_PRECISE = (1 << 0),
};
bool wm_widget_register(wmWidgetGroup *wgroup, struct wmWidget *widget, const char *name);
bool wm_widget_deselect(struct wmWidgetMap *wmap, struct wmWidget *widget);
bool wm_widget_select(bContext *C, struct wmWidgetMap *wmap, struct wmWidget *widget);
void wm_widget_calculate_scale(struct wmWidget *widget, const bContext *C);
void wm_widget_update_prop_data(struct wmWidget *widget);
void fix_linking_widget_arrow(void);
void fix_linking_widget_arrow2d(void);
void fix_linking_widget_cage(void);
void fix_linking_widget_dial(void);
void fix_linking_widget_facemap(void);
void fix_linking_widget_primitive(void);
/* -------------------------------------------------------------------- */
/* wmWidgetGroup */
enum {
TWEAK_MODAL_CANCEL = 1,
TWEAK_MODAL_CONFIRM,
TWEAK_MODAL_PRECISION_ON,
TWEAK_MODAL_PRECISION_OFF,
};
void wm_widgetgroup_free(bContext *C, wmWidgetMap *wmap, struct wmWidgetGroup *wgroup);
void wm_widgetgrouptype_keymap_init(struct wmWidgetGroupType *wgrouptype, struct wmKeyConfig *keyconf);
/* -------------------------------------------------------------------- */
/* wmWidgetMap */
/**
* This is a container for all widget types that can be instantiated in a region.
* (similar to dropboxes).
*
* \note There is only ever one of these for every (area, region) combination.
*/
typedef struct wmWidgetMapType {
struct wmWidgetMapType *next, *prev;
char idname[64];
short spaceid, regionid;
/* widgetTypeflags */
int flag;
/* types of widgetgroups for this widgetmap type */
ListBase widgetgrouptypes;
} wmWidgetMapType;
void wm_widgetmap_selected_delete(wmWidgetMap *wmap);
/* -------------------------------------------------------------------- */
/* Widget drawing */
typedef struct WidgetDrawInfo {
int nverts;
int ntris;
float (*verts)[3];
float (*normals)[3];
unsigned short *indices;
bool init;
} WidgetDrawInfo;
void widget_draw_intern(WidgetDrawInfo *info, const bool select);
#endif /* __WM_WIDGET_INTERN_H__ */

View File

@@ -0,0 +1,514 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2014 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/wm_widgetgroup.c
* \ingroup wm
*
* \name Widget Group
*
* WidgetGroups store and manage groups of widgets. They can be
* attached to modal handlers and have on keymaps.
*/
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BPY_extern.h"
#include "ED_screen.h"
#include "MEM_guardedalloc.h"
#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm_event_system.h"
/* own includes */
#include "wm_widget_wmapi.h"
#include "wm_widget_intern.h"
/* -------------------------------------------------------------------- */
/** \name wmWidgetGroup
*
* \{ */
void wm_widgetgroup_free(bContext *C, wmWidgetMap *wmap, wmWidgetGroup *wgroup)
{
for (wmWidget *widget = wgroup->widgets.first; widget;) {
wmWidget *widget_next = widget->next;
WM_widget_delete(&wgroup->widgets, wmap, widget, C);
widget = widget_next;
}
BLI_assert(BLI_listbase_is_empty(&wgroup->widgets));
#ifdef WITH_PYTHON
if (wgroup->py_instance) {
/* do this first in case there are any __del__ functions or
* similar that use properties */
BPY_DECREF_RNA_INVALIDATE(wgroup->py_instance);
}
#endif
if (wgroup->reports && (wgroup->reports->flag & RPT_FREE)) {
BKE_reports_clear(wgroup->reports);
MEM_freeN(wgroup->reports);
}
if (wgroup->customdata_free) {
wgroup->customdata_free(wgroup->customdata);
}
else {
MEM_SAFE_FREE(wgroup->customdata);
}
BLI_remlink(&wmap->widgetgroups, wgroup);
MEM_freeN(wgroup);
}
void wm_widgetgroup_attach_to_modal_handler(bContext *C, wmEventHandler *handler,
wmWidgetGroupType *wgrouptype, wmOperator *op)
{
/* maybe overly careful, but widgetgrouptype could come from a failed creation */
if (!wgrouptype) {
return;
}
/* now instantiate the widgetmap */
wgrouptype->op = op;
if (handler->op_region && !BLI_listbase_is_empty(&handler->op_region->widgetmaps)) {
for (wmWidgetMap *wmap = handler->op_region->widgetmaps.first; wmap; wmap = wmap->next) {
wmWidgetMapType *wmaptype = wmap->type;
if (wmaptype->spaceid == wgrouptype->spaceid && wmaptype->regionid == wgrouptype->regionid) {
handler->widgetmap = wmap;
}
}
ED_region_tag_redraw(handler->op_region);
}
WM_event_add_mousemove(C);
}
/** \name Widget operators
*
* Basic operators for widget interaction with user configurable keymaps.
*
* \{ */
static int widget_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
ARegion *ar = CTX_wm_region(C);
bool extend = RNA_boolean_get(op->ptr, "extend");
bool deselect = RNA_boolean_get(op->ptr, "deselect");
bool toggle = RNA_boolean_get(op->ptr, "toggle");
for (wmWidgetMap *wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) {
wmWidget ***sel = &wmap->wmap_context.selected_widgets;
wmWidget *highlighted = wmap->wmap_context.highlighted_widget;
/* deselect all first */
if (extend == false && deselect == false && toggle == false) {
wm_widgetmap_deselect_all(wmap, sel);
BLI_assert(*sel == NULL && wmap->wmap_context.tot_selected == 0);
}
if (highlighted) {
const bool is_selected = (highlighted->flag & WM_WIDGET_SELECTED);
bool redraw = false;
if (toggle) {
/* toggle: deselect if already selected, else select */
deselect = is_selected;
}
if (deselect) {
if (is_selected && wm_widget_deselect(wmap, highlighted)) {
redraw = true;
}
}
else if (wm_widget_select(C, wmap, highlighted)) {
redraw = true;
}
if (redraw) {
ED_region_tag_redraw(ar);
}
return OPERATOR_FINISHED;
}
else {
BLI_assert(0);
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
}
return OPERATOR_PASS_THROUGH;
}
void WIDGETGROUP_OT_widget_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Widget Select";
ot->description = "Select the currently highlighted widget";
ot->idname = "WIDGETGROUP_OT_widget_select";
/* api callbacks */
ot->invoke = widget_select_invoke;
ot->flag = OPTYPE_UNDO;
WM_operator_properties_mouse_select(ot);
}
typedef struct WidgetTweakData {
wmWidgetMap *wmap;
wmWidget *active;
int init_event; /* initial event type */
int flag; /* tweak flags */
} WidgetTweakData;
static void widget_tweak_finish(bContext *C, wmOperator *op, const bool cancel)
{
WidgetTweakData *wtweak = op->customdata;
if (wtweak->active->exit) {
wtweak->active->exit(C, wtweak->active, cancel);
}
wm_widgetmap_set_active_widget(wtweak->wmap, C, NULL, NULL);
MEM_freeN(wtweak);
}
static int widget_tweak_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
WidgetTweakData *wtweak = op->customdata;
wmWidget *widget = wtweak->active;
if (!widget) {
BLI_assert(0);
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
if (event->type == wtweak->init_event && event->val == KM_RELEASE) {
widget_tweak_finish(C, op, false);
return OPERATOR_FINISHED;
}
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case TWEAK_MODAL_CANCEL:
widget_tweak_finish(C, op, true);
return OPERATOR_CANCELLED;
case TWEAK_MODAL_CONFIRM:
widget_tweak_finish(C, op, false);
return OPERATOR_FINISHED;
case TWEAK_MODAL_PRECISION_ON:
wtweak->flag |= WM_WIDGET_TWEAK_PRECISE;
break;
case TWEAK_MODAL_PRECISION_OFF:
wtweak->flag &= ~WM_WIDGET_TWEAK_PRECISE;
break;
}
}
/* handle widget */
if (widget->handler) {
widget->handler(C, event, widget, wtweak->flag);
}
/* Ugly hack to send widget events */
((wmEvent *)event)->type = EVT_WIDGET_UPDATE;
/* always return PASS_THROUGH so modal handlers
* with widgets attached can update */
return OPERATOR_PASS_THROUGH;
}
static int widget_tweak_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
wmWidgetMap *wmap;
wmWidget *widget;
for (wmap = ar->widgetmaps.first; wmap; wmap = wmap->next)
if ((widget = wmap->wmap_context.highlighted_widget))
break;
if (!widget) {
/* wm_handlers_do_intern shouldn't let this happen */
BLI_assert(0);
return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH);
}
/* activate highlighted widget */
wm_widgetmap_set_active_widget(wmap, C, event, widget);
/* XXX temporary workaround for modal widget operator
* conflicting with modal operator attached to widget */
if (widget->opname) {
wmOperatorType *ot = WM_operatortype_find(widget->opname, true);
if (ot->modal) {
return OPERATOR_FINISHED;
}
}
WidgetTweakData *wtweak = MEM_mallocN(sizeof(WidgetTweakData), __func__);
wtweak->init_event = event->type;
wtweak->active = wmap->wmap_context.highlighted_widget;
wtweak->wmap = wmap;
wtweak->flag = 0;
op->customdata = wtweak;
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
void WIDGETGROUP_OT_widget_tweak(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Widget Tweak";
ot->description = "Tweak the active widget";
ot->idname = "WIDGETGROUP_OT_widget_tweak";
/* api callbacks */
ot->invoke = widget_tweak_invoke;
ot->modal = widget_tweak_modal;
ot->flag = OPTYPE_UNDO;
}
/** \} */ // Widget operators
static wmKeyMap *widgetgroup_tweak_modal_keymap(wmKeyConfig *keyconf, const char *wgroupname)
{
wmKeyMap *keymap;
char name[KMAP_MAX_NAME];
static EnumPropertyItem modal_items[] = {
{TWEAK_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
{TWEAK_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
{TWEAK_MODAL_PRECISION_ON, "PRECISION_ON", 0, "Enable Precision", ""},
{TWEAK_MODAL_PRECISION_OFF, "PRECISION_OFF", 0, "Disable Precision", ""},
{0, NULL, 0, NULL, NULL}
};
BLI_snprintf(name, sizeof(name), "%s Tweak Modal Map", wgroupname);
keymap = WM_modalkeymap_get(keyconf, name);
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items)
return NULL;
keymap = WM_modalkeymap_add(keyconf, name, modal_items);
/* items for modal map */
WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL);
WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM);
WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CONFIRM);
WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON);
WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF);
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_PRECISION_ON);
WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, TWEAK_MODAL_PRECISION_OFF);
WM_modalkeymap_assign(keymap, "WIDGETGROUP_OT_widget_tweak");
return keymap;
}
/**
* Common default keymap for widget groups
*/
wmKeyMap *WM_widgetgroup_keymap_common(const struct wmWidgetGroupType *wgrouptype, wmKeyConfig *config)
{
/* Use area and region id since we might have multiple widgets with the same name in different areas/regions */
wmKeyMap *km = WM_keymap_find(config, wgrouptype->name, wgrouptype->spaceid, wgrouptype->regionid);
WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0);
widgetgroup_tweak_modal_keymap(config, wgrouptype->name);
return km;
}
/**
* Variation of #WM_widgetgroup_keymap_common but with keymap items for selection
*/
wmKeyMap *WM_widgetgroup_keymap_common_sel(const struct wmWidgetGroupType *wgrouptype, wmKeyConfig *config)
{
/* Use area and region id since we might have multiple widgets with the same name in different areas/regions */
wmKeyMap *km = WM_keymap_find(config, wgrouptype->name, wgrouptype->spaceid, wgrouptype->regionid);
WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_tweak", ACTIONMOUSE, KM_PRESS, KM_ANY, 0);
widgetgroup_tweak_modal_keymap(config, wgrouptype->name);
wmKeyMapItem *kmi = WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_select", SELECTMOUSE, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "extend", false);
RNA_boolean_set(kmi->ptr, "deselect", false);
RNA_boolean_set(kmi->ptr, "toggle", false);
kmi = WM_keymap_add_item(km, "WIDGETGROUP_OT_widget_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", false);
RNA_boolean_set(kmi->ptr, "deselect", false);
RNA_boolean_set(kmi->ptr, "toggle", true);
return km;
}
/** \} */ /* wmWidgetGroup */
/* -------------------------------------------------------------------- */
/** \name wmWidgetGroupType
*
* \{ */
/**
* Use this for registering widgets on startup. For runtime, use #WM_widgetgrouptype_append_runtime.
*/
wmWidgetGroupType *WM_widgetgrouptype_append(wmWidgetMapType *wmaptype, void (*wgrouptype_func)(wmWidgetGroupType *))
{
wmWidgetGroupType *wgrouptype = MEM_callocN(sizeof(wmWidgetGroupType), "widgetgroup");
wgrouptype_func(wgrouptype);
wgrouptype->spaceid = wmaptype->spaceid;
wgrouptype->regionid = wmaptype->regionid;
wgrouptype->flag = wmaptype->flag;
BLI_strncpy(wgrouptype->mapidname, wmaptype->idname, MAX_NAME);
/* if not set, use default */
if (!wgrouptype->keymap_init) {
wgrouptype->keymap_init = WM_widgetgroup_keymap_common;
}
/* add the type for future created areas of the same type */
BLI_addtail(&wmaptype->widgetgrouptypes, wgrouptype);
return wgrouptype;
}
/**
* Use this for registering widgets on runtime.
*/
wmWidgetGroupType *WM_widgetgrouptype_append_runtime(
const Main *main, wmWidgetMapType *wmaptype,
void (*wgrouptype_func)(wmWidgetGroupType *))
{
wmWidgetGroupType *wgrouptype = WM_widgetgrouptype_append(wmaptype, wgrouptype_func);
/* Main is missing on startup when we create new areas.
* So this is only called for widgets initialized on runtime */
WM_widgetgrouptype_init_runtime(main, wmaptype, wgrouptype);
return wgrouptype;
}
void WM_widgetgrouptype_init_runtime(
const Main *bmain, wmWidgetMapType *wmaptype,
wmWidgetGroupType *wgrouptype)
{
/* init keymap - on startup there's an extra call to init keymaps for 'permanent' widget-groups */
wm_widgetgrouptype_keymap_init(wgrouptype, ((wmWindowManager *)bmain->wm.first)->defaultconf);
/* now create a widget for all existing areas */
for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
for (ARegion *ar = lb->first; ar; ar = ar->next) {
for (wmWidgetMap *wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) {
if (wmap->type == wmaptype) {
wmWidgetGroup *wgroup = MEM_callocN(sizeof(wmWidgetGroup), "widgetgroup");
wgroup->type = wgrouptype;
/* just add here, drawing will occur on next update */
BLI_addtail(&wmap->widgetgroups, wgroup);
wm_widgetmap_set_highlighted_widget(wmap, NULL, NULL, 0);
ED_region_tag_redraw(ar);
}
}
}
}
}
}
}
void WM_widgetgrouptype_unregister(bContext *C, Main *bmain, wmWidgetGroupType *wgrouptype)
{
for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) {
for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
for (ARegion *ar = lb->first; ar; ar = ar->next) {
for (wmWidgetMap *wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) {
wmWidgetGroup *wgroup, *wgroup_next;
for (wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup_next) {
wgroup_next = wgroup->next;
if (wgroup->type == wgrouptype) {
wm_widgetgroup_free(C, wmap, wgroup);
ED_region_tag_redraw(ar);
}
}
}
}
}
}
}
wmWidgetMapType *wmaptype = WM_widgetmaptype_find(&(const struct wmWidgetMapType_Params) {
wgrouptype->mapidname, wgrouptype->spaceid,
wgrouptype->regionid, wgrouptype->flag});
BLI_remlink(&wmaptype->widgetgrouptypes, wgrouptype);
wgrouptype->prev = wgrouptype->next = NULL;
MEM_freeN(wgrouptype);
}
void wm_widgetgrouptype_keymap_init(wmWidgetGroupType *wgrouptype, wmKeyConfig *keyconf)
{
wgrouptype->keymap = wgrouptype->keymap_init(wgrouptype, keyconf);
}
/** \} */ /* wmWidgetGroupType */

View File

@@ -0,0 +1,826 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2014 Blender Foundation.
* All rights reserved.
*
* Contributor(s): Blender Foundation
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/intern/wm_widgetmap.c
* \ingroup wm
*/
#include <string.h>
#include "BKE_context.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_ghash.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "GL/glew.h"
#include "GPU_select.h"
#include "MEM_guardedalloc.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm_event_system.h"
/* own includes */
#include "wm_widget_wmapi.h"
#include "wm_widget_intern.h"
/**
* Store all widgetboxmaps here. Anyone who wants to register a widget for a certain
* area type can query the widget map to do so.
*/
static ListBase widgetmaptypes = {NULL, NULL};
/**
* List of all visible widgets to avoid unnecessary loops and wmWidgetGroupType->poll checks.
* Collected in WM_widgets_update.
*/
static ListBase draw_widgets = {NULL, NULL};
/**
* Widget map update/init tagging.
*/
enum eWidgetMapUpdateFlags {
/* Set to init widget map. Should only be the case on first draw. */
WIDGETMAP_INIT = (1 << 0),
/* Tag widget map for refresh. */
WIDGETMAP_REFRESH = (1 << 1),
};
/* -------------------------------------------------------------------- */
/** \name wmWidgetMap
*
* \{ */
/**
* creates a widgetmap with all registered widgets for that type
*/
wmWidgetMap *WM_widgetmap_from_type(const struct wmWidgetMapType_Params *wmap_params)
{
wmWidgetMapType *wmaptype = WM_widgetmaptype_ensure(wmap_params);
wmWidgetMap *wmap;
wmap = MEM_callocN(sizeof(wmWidgetMap), "WidgetMap");
wmap->type = wmaptype;
wmap->update_flag |= (WIDGETMAP_INIT | WIDGETMAP_REFRESH);
/* create all widgetgroups for this widgetmap. We may create an empty one
* too in anticipation of widgets from operators etc */
for (wmWidgetGroupType *wgrouptype = wmaptype->widgetgrouptypes.first; wgrouptype; wgrouptype = wgrouptype->next) {
wmWidgetGroup *wgroup = MEM_callocN(sizeof(wmWidgetGroup), "widgetgroup");
wgroup->type = wgrouptype;
BLI_addtail(&wmap->widgetgroups, wgroup);
}
return wmap;
}
void wm_widgetmap_selected_delete(wmWidgetMap *wmap)
{
MEM_SAFE_FREE(wmap->wmap_context.selected_widgets);
wmap->wmap_context.tot_selected = 0;
}
void WM_widgetmap_delete(wmWidgetMap *wmap)
{
if (!wmap)
return;
for (wmWidgetGroup *wgroup = wmap->widgetgroups.first, *wgroup_next; wgroup; wgroup = wgroup_next) {
wgroup_next = wgroup->next;
wm_widgetgroup_free(NULL, wmap, wgroup);
}
BLI_assert(BLI_listbase_is_empty(&wmap->widgetgroups));
wm_widgetmap_selected_delete(wmap);
MEM_freeN(wmap);
}
wmWidgetMap *WM_widgetmap_find(
const ARegion *ar, const struct wmWidgetMapType_Params *wmap_params)
{
for (wmWidgetMap *wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) {
const wmWidgetMapType *wmaptype = wmap->type;
if (wmaptype->spaceid == wmap_params->spaceid &&
wmaptype->regionid == wmap_params->regionid &&
STREQ(wmaptype->idname, wmap_params->idname))
{
return wmap;
}
}
return NULL;
}
/**
* Creates and returns idname hash table for (visible) widgets in \a wmap
*
* \param poll Polling function for excluding widgets.
* \param data Custom data passed to \a poll
*/
static GHash *wm_widgetmap_widget_hash_new(
const bContext *C, wmWidgetMap *wmap,
bool (*poll)(const wmWidget *, void *),
void *data, const bool include_hidden)
{
GHash *hash = BLI_ghash_str_new(__func__);
/* collect widgets */
for (wmWidgetGroup *wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) {
if (!wgroup->type->poll || wgroup->type->poll(C, wgroup->type)) {
for (wmWidget *widget = wgroup->widgets.first; widget; widget = widget->next) {
if ((include_hidden || (widget->flag & WM_WIDGET_HIDDEN) == 0) &&
(!poll || poll(widget, data)))
{
BLI_ghash_insert(hash, widget->idname, widget);
}
}
}
}
return hash;
}
void WM_widgetmap_tag_refresh(wmWidgetMap *wmap)
{
if (wmap) {
wmap->update_flag |= WIDGETMAP_REFRESH;
}
}
void WM_widgetmap_widgets_update(const bContext *C, wmWidgetMap *wmap)
{
if (!wmap || BLI_listbase_is_empty(&wmap->widgetgroups))
return;
/* only active widget needs updating */
if (wmap->wmap_context.active_widget) {
wm_widget_calculate_scale(wmap->wmap_context.active_widget, C);
goto done;
}
for (wmWidgetGroup *wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) {
if ((wgroup->type->flag & WM_WIDGETGROUPTYPE_OP && !wgroup->type->op) || /* only while operator runs */
(wgroup->type->poll && !wgroup->type->poll(C, wgroup->type)))
continue;
/* prepare for first draw */
if (UNLIKELY((wgroup->flag & WM_WIDGETGROUP_INITIALIZED) == 0)) {
wgroup->type->init(C, wgroup);
wgroup->flag |= WM_WIDGETGROUP_INITIALIZED;
}
/* update data if needed */
if (wmap->update_flag & WIDGETMAP_REFRESH && wgroup->type->refresh) {
wgroup->type->refresh(C, wgroup);
}
/* prepare drawing */
if (wgroup->type->draw_prepare) {
wgroup->type->draw_prepare(C, wgroup);
}
for (wmWidget *widget = wgroup->widgets.first; widget; widget = widget->next) {
if (widget->flag & WM_WIDGET_HIDDEN)
continue;
if (wmap->update_flag & WIDGETMAP_REFRESH) {
wm_widget_update_prop_data(widget);
}
wm_widget_calculate_scale(widget, C);
BLI_addhead(&draw_widgets, BLI_genericNodeN(widget));
}
}
done:
/* done updating */
wmap->update_flag = 0;
}
/**
* Draw all visible widgets in \a wmap.
* Uses global draw_widgets listbase.
*
* \param in_scene draw depth-culled widgets (wmWidget->flag WM_WIDGET_SCENE_DEPTH) - TODO
* \param free_drawwidgets free global draw_widgets listbase (always enable for last draw call in region!).
*/
void WM_widgetmap_widgets_draw(
const bContext *C, const wmWidgetMap *wmap,
const bool in_scene, const bool free_drawwidgets)
{
BLI_assert(!BLI_listbase_is_empty(&wmap->widgetgroups));
if (!wmap)
return;
const bool draw_multisample = (U.ogl_multisamples != USER_MULTISAMPLE_NONE);
const bool use_lighting = (U.widget_flag & V3D_SHADED_WIDGETS) != 0;
/* enable multisampling */
if (draw_multisample) {
glEnable(GL_MULTISAMPLE);
}
if (use_lighting) {
const float lightpos[4] = {0.0, 0.0, 1.0, 0.0};
const float diffuse[4] = {1.0, 1.0, 1.0, 0.0};
glPushAttrib(GL_LIGHTING_BIT | GL_ENABLE_BIT);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
glPushMatrix();
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glPopMatrix();
}
wmWidget *widget = wmap->wmap_context.active_widget;
/* draw active widget */
if (widget && in_scene == (widget->flag & WM_WIDGET_SCENE_DEPTH)) {
if (widget->flag & (WM_WIDGET_DRAW_ACTIVE | WM_WIDGET_DRAW_VALUE)) {
/* notice that we don't update the widgetgroup, widget is now on
* its own, it should have all relevant data to update itself */
widget->draw(C, widget);
}
}
/* draw selected widgets */
if (wmap->wmap_context.selected_widgets) {
for (int i = 0; i < wmap->wmap_context.tot_selected; i++) {
widget = wmap->wmap_context.selected_widgets[i];
if ((widget != NULL) &&
(widget->flag & WM_WIDGET_HIDDEN) == 0 &&
(in_scene == (widget->flag & WM_WIDGET_SCENE_DEPTH)))
{
/* notice that we don't update the widgetgroup, widget is now on
* its own, it should have all relevant data to update itself */
widget->draw(C, widget);
}
}
}
/* draw other widgets */
if (!wmap->wmap_context.active_widget) {
/* draw_widgets excludes hidden widgets */
for (LinkData *link = draw_widgets.first; link; link = link->next) {
widget = link->data;
if ((in_scene == (widget->flag & WM_WIDGET_SCENE_DEPTH)) &&
((widget->flag & WM_WIDGET_SELECTED) == 0) && /* selected were drawn already */
((widget->flag & WM_WIDGET_DRAW_HOVER) == 0 || (widget->flag & WM_WIDGET_HIGHLIGHT)))
{
widget->draw(C, widget);
}
}
}
if (draw_multisample)
glDisable(GL_MULTISAMPLE);
if (use_lighting)
glPopAttrib();
if (free_drawwidgets) {
BLI_freelistN(&draw_widgets);
}
}
static void widget_find_active_3D_loop(const bContext *C, ListBase *visible_widgets)
{
int selectionbase = 0;
wmWidget *widget;
for (LinkData *link = visible_widgets->first; link; link = link->next) {
widget = link->data;
/* pass the selection id shifted by 8 bits. Last 8 bits are used for selected widget part id */
widget->render_3d_intersection(C, widget, selectionbase << 8);
selectionbase++;
}
}
static int widget_find_highlighted_3D_intern(
ListBase *visible_widgets, const bContext *C, const wmEvent *event, const float hotspot)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
rctf rect, selrect;
GLuint buffer[64]; // max 4 items per select, so large enuf
short hits;
const bool do_passes = GPU_select_query_check_active();
extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect);
rect.xmin = event->mval[0] - hotspot;
rect.xmax = event->mval[0] + hotspot;
rect.ymin = event->mval[1] - hotspot;
rect.ymax = event->mval[1] + hotspot;
selrect = rect;
view3d_winmatrix_set(ar, v3d, &rect);
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
if (do_passes)
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
else
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_ALL, 0);
/* do the drawing */
widget_find_active_3D_loop(C, visible_widgets);
hits = GPU_select_end();
if (do_passes) {
GPU_select_begin(buffer, ARRAY_SIZE(buffer), &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
widget_find_active_3D_loop(C, visible_widgets);
GPU_select_end();
}
view3d_winmatrix_set(ar, v3d, NULL);
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
return hits > 0 ? buffer[3] : -1;
}
static void widgets_prepare_visible_3D(wmWidgetMap *wmap, ListBase *visible_widgets, bContext *C)
{
wmWidget *widget;
for (wmWidgetGroup *wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) {
if (!wgroup->type->poll || wgroup->type->poll(C, wgroup->type)) {
for (widget = wgroup->widgets.first; widget; widget = widget->next) {
if (widget->render_3d_intersection && (widget->flag & WM_WIDGET_HIDDEN) == 0) {
BLI_addhead(visible_widgets, BLI_genericNodeN(widget));
}
}
}
}
}
wmWidget *wm_widgetmap_find_highlighted_3D(wmWidgetMap *wmap, bContext *C, const wmEvent *event, unsigned char *part)
{
wmWidget *result = NULL;
ListBase visible_widgets = {0};
const float hotspot = 14.0f;
int ret;
widgets_prepare_visible_3D(wmap, &visible_widgets, C);
*part = 0;
/* set up view matrices */
view3d_operator_needs_opengl(C);
ret = widget_find_highlighted_3D_intern(&visible_widgets, C, event, 0.5f * hotspot);
if (ret != -1) {
LinkData *link;
int retsec;
retsec = widget_find_highlighted_3D_intern(&visible_widgets, C, event, 0.2f * hotspot);
if (retsec != -1)
ret = retsec;
link = BLI_findlink(&visible_widgets, ret >> 8);
*part = ret & 255;
result = link->data;
}
BLI_freelistN(&visible_widgets);
return result;
}
void WM_widgetmaps_add_handlers(ARegion *ar)
{
for (wmWidgetMap *wmap = ar->widgetmaps.first; wmap; wmap = wmap->next) {
wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "widget handler");
handler->widgetmap = wmap;
BLI_addtail(&ar->handlers, handler);
}
}
void wm_widgetmaps_handled_modal_update(
bContext *C, wmEvent *event, wmEventHandler *handler,
const wmOperatorType *ot)
{
const bool modal_running = (handler->op != NULL);
/* happens on render */
if (!handler->op_region)
return;
/* hide operator widgets */
if (!modal_running && ot->wgrouptype) {
ot->wgrouptype->op = NULL;
}
for (wmWidgetMap *wmap = handler->op_region->widgetmaps.first; wmap; wmap = wmap->next) {
wmWidget *widget = wm_widgetmap_get_active_widget(wmap);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
wm_widgetmap_handler_context(C, handler);
/* regular update for running operator */
if (modal_running) {
if (widget && widget->handler && widget->opname && STREQ(widget->opname, handler->op->idname)) {
widget->handler(C, event, widget, 0);
}
}
/* operator not running anymore */
else {
wm_widgetmap_set_highlighted_widget(wmap, C, NULL, 0);
wm_widgetmap_set_active_widget(wmap, C, event, NULL);
}
/* restore the area */
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
}
}
/**
* Deselect all selected widgets in \a wmap.
* \return if selection has changed.
*/
bool wm_widgetmap_deselect_all(wmWidgetMap *wmap, wmWidget ***sel)
{
if (*sel == NULL || wmap->wmap_context.tot_selected == 0)
return false;
for (int i = 0; i < wmap->wmap_context.tot_selected; i++) {
(*sel)[i]->flag &= ~WM_WIDGET_SELECTED;
(*sel)[i] = NULL;
}
wm_widgetmap_selected_delete(wmap);
/* always return true, we already checked
* if there's anything to deselect */
return true;
}
BLI_INLINE bool widget_selectable_poll(const wmWidget *widget, void *UNUSED(data))
{
return (widget->flag & WM_WIDGET_SELECTABLE);
}
/**
* Select all selectable widgets in \a wmap.
* \return if selection has changed.
*/
static bool wm_widgetmap_select_all_intern(bContext *C, wmWidgetMap *wmap, wmWidget ***sel, const int action)
{
/* GHash is used here to avoid having to loop over all widgets twice (once to
* get tot_sel for allocating, once for actually selecting). Instead we collect
* selectable widgets in hash table and use this to get tot_sel and do selection */
GHash *hash = wm_widgetmap_widget_hash_new(C, wmap, widget_selectable_poll, NULL, true);
GHashIterator gh_iter;
int i, *tot_sel = &wmap->wmap_context.tot_selected;
bool changed = false;
*tot_sel = BLI_ghash_size(hash);
*sel = MEM_reallocN(*sel, sizeof(**sel) * (*tot_sel));
GHASH_ITER_INDEX (gh_iter, hash, i) {
wmWidget *widget_iter = BLI_ghashIterator_getValue(&gh_iter);
if ((widget_iter->flag & WM_WIDGET_SELECTED) == 0) {
changed = true;
}
widget_iter->flag |= WM_WIDGET_SELECTED;
if (widget_iter->select) {
widget_iter->select(C, widget_iter, action);
}
(*sel)[i] = widget_iter;
BLI_assert(i < (*tot_sel));
}
/* highlight first widget */
wm_widgetmap_set_highlighted_widget(wmap, C, (*sel)[0], (*sel)[0]->highlighted_part);
BLI_ghash_free(hash, NULL, NULL);
return changed;
}
/**
* Select/Deselect all selectable widgets in \a wmap.
* \return if selection has changed.
*
* TODO select all by type
*/
bool WM_widgetmap_select_all(bContext *C, wmWidgetMap *wmap, const int action)
{
wmWidget ***sel = &wmap->wmap_context.selected_widgets;
bool changed = false;
switch (action) {
case SEL_SELECT:
changed = wm_widgetmap_select_all_intern(C, wmap, sel, action);
break;
case SEL_DESELECT:
changed = wm_widgetmap_deselect_all(wmap, sel);
break;
default:
BLI_assert(0);
break;
}
if (changed)
WM_event_add_mousemove(C);
return changed;
}
bool wm_widgetmap_is_3d(const wmWidgetMap *wmap)
{
return (wmap->type->flag & WM_WIDGETMAPTYPE_3D) != 0;
}
void wm_widgetmap_handler_context(bContext *C, wmEventHandler *handler)
{
bScreen *screen = CTX_wm_screen(C);
if (screen) {
if (handler->op_area == NULL) {
/* do nothing in this context */
}
else {
ScrArea *sa;
for (sa = screen->areabase.first; sa; sa = sa->next)
if (sa == handler->op_area)
break;
if (sa == NULL) {
/* when changing screen layouts with running modal handlers (like render display), this
* is not an error to print */
if (handler->widgetmap == NULL)
printf("internal error: modal widgetmap handler has invalid area\n");
}
else {
ARegion *ar;
CTX_wm_area_set(C, sa);
for (ar = sa->regionbase.first; ar; ar = ar->next)
if (ar == handler->op_region)
break;
/* XXX no warning print here, after full-area and back regions are remade */
if (ar)
CTX_wm_region_set(C, ar);
}
}
}
}
wmWidget *wm_widgetmap_find_highlighted_widget(wmWidgetMap *wmap, bContext *C, const wmEvent *event, unsigned char *part)
{
wmWidget *widget;
for (wmWidgetGroup *wgroup = wmap->widgetgroups.first; wgroup; wgroup = wgroup->next) {
if (!wgroup->type->poll || wgroup->type->poll(C, wgroup->type)) {
for (widget = wgroup->widgets.first; widget; widget = widget->next) {
if (widget->intersect) {
if ((*part = widget->intersect(C, event, widget)))
return widget;
}
}
}
}
return NULL;
}
bool WM_widgetmap_cursor_set(const wmWidgetMap *wmap, wmWindow *win)
{
for (; wmap; wmap = wmap->next) {
wmWidget *widget = wmap->wmap_context.highlighted_widget;
if (widget && widget->get_cursor) {
WM_cursor_set(win, widget->get_cursor(widget));
return true;
}
}
return false;
}
void wm_widgetmap_set_highlighted_widget(wmWidgetMap *wmap, const bContext *C, wmWidget *widget, unsigned char part)
{
if ((widget != wmap->wmap_context.highlighted_widget) || (widget && part != widget->highlighted_part)) {
if (wmap->wmap_context.highlighted_widget) {
wmap->wmap_context.highlighted_widget->flag &= ~WM_WIDGET_HIGHLIGHT;
wmap->wmap_context.highlighted_widget->highlighted_part = 0;
}
wmap->wmap_context.highlighted_widget = widget;
if (widget) {
widget->flag |= WM_WIDGET_HIGHLIGHT;
widget->highlighted_part = part;
wmap->wmap_context.activegroup = widget->wgroup;
if (C && widget->get_cursor) {
wmWindow *win = CTX_wm_window(C);
WM_cursor_set(win, widget->get_cursor(widget));
}
}
else {
wmap->wmap_context.activegroup = NULL;
if (C) {
wmWindow *win = CTX_wm_window(C);
WM_cursor_set(win, CURSOR_STD);
}
}
/* tag the region for redraw */
if (C) {
ARegion *ar = CTX_wm_region(C);
ED_region_tag_redraw(ar);
}
}
}
wmWidget *wm_widgetmap_get_highlighted_widget(wmWidgetMap *wmap)
{
return wmap->wmap_context.highlighted_widget;
}
void wm_widgetmap_set_active_widget(wmWidgetMap *wmap, bContext *C, const wmEvent *event, wmWidget *widget)
{
if (widget && C) {
widget->flag |= WM_WIDGET_ACTIVE;
wmap->wmap_context.active_widget = widget;
if (widget->opname) {
wmOperatorType *ot = WM_operatortype_find(widget->opname, 0);
if (ot) {
/* first activate the widget itself */
if (widget->invoke && widget->handler) {
widget->invoke(C, event, widget);
}
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &widget->opptr);
/* we failed to hook the widget to the operator handler or operator was cancelled, return */
if (!wmap->wmap_context.active_widget) {
widget->flag &= ~WM_WIDGET_ACTIVE;
/* first activate the widget itself */
if (widget->interaction_data) {
MEM_freeN(widget->interaction_data);
widget->interaction_data = NULL;
}
}
return;
}
else {
printf("Widget error: operator not found");
wmap->wmap_context.active_widget = NULL;
return;
}
}
else {
if (widget->invoke && widget->handler) {
widget->invoke(C, event, widget);
}
}
WM_cursor_grab_enable(CTX_wm_window(C), true, true, NULL);
}
else {
widget = wmap->wmap_context.active_widget;
/* deactivate, widget but first take care of some stuff */
if (widget) {
widget->flag &= ~WM_WIDGET_ACTIVE;
/* first activate the widget itself */
if (widget->interaction_data) {
MEM_freeN(widget->interaction_data);
widget->interaction_data = NULL;
}
}
wmap->wmap_context.active_widget = NULL;
if (C) {
WM_cursor_grab_disable(CTX_wm_window(C), NULL);
ED_region_tag_redraw(CTX_wm_region(C));
WM_event_add_mousemove(C);
}
}
}
wmWidget *wm_widgetmap_get_active_widget(wmWidgetMap *wmap)
{
return wmap->wmap_context.active_widget;
}
/** \} */ /* wmWidgetMap */
/* -------------------------------------------------------------------- */
/** \name wmWidgetMapType
*
* \{ */
wmWidgetMapType *WM_widgetmaptype_find(
const struct wmWidgetMapType_Params *wmap_params)
{
wmWidgetMapType *wmaptype;
/* flags which differentiates widget groups */
const int flag_cmp = WM_WIDGETMAPTYPE_3D;
const int flag_test = wmap_params->flag & flag_cmp;
for (wmaptype = widgetmaptypes.first; wmaptype; wmaptype = wmaptype->next) {
if (wmaptype->spaceid == wmap_params->spaceid &&
wmaptype->regionid == wmap_params->regionid &&
((wmaptype->flag & flag_cmp) == flag_test) &&
STREQ(wmaptype->idname, wmap_params->idname))
{
return wmaptype;
}
}
return NULL;
}
wmWidgetMapType *WM_widgetmaptype_ensure(
const struct wmWidgetMapType_Params *wmap_params)
{
wmWidgetMapType *wmaptype = WM_widgetmaptype_find(wmap_params);
if (wmaptype) {
return wmaptype;
}
wmaptype = MEM_callocN(sizeof(wmWidgetMapType), "widgettype list");
wmaptype->spaceid = wmap_params->spaceid;
wmaptype->regionid = wmap_params->regionid;
wmaptype->flag = wmap_params->flag;
BLI_strncpy(wmaptype->idname, wmap_params->idname, sizeof(wmaptype->idname));
BLI_addhead(&widgetmaptypes, wmaptype);
return wmaptype;
}
void WM_widgetmaptypes_free(void)
{
for (wmWidgetMapType *wmaptype = widgetmaptypes.first; wmaptype; wmaptype = wmaptype->next) {
BLI_freelistN(&wmaptype->widgetgrouptypes);
}
BLI_freelistN(&widgetmaptypes);
}
/**
* Initialize keymaps for all existing widget-groups
*/
void wm_widgets_keymap(wmKeyConfig *keyconf)
{
wmWidgetMapType *wmaptype;
wmWidgetGroupType *wgrouptype;
/* we add this item-less keymap once and use it to group widgetgroup keymaps into it */
WM_keymap_find(keyconf, "Widgets", 0, 0);
for (wmaptype = widgetmaptypes.first; wmaptype; wmaptype = wmaptype->next) {
for (wgrouptype = wmaptype->widgetgrouptypes.first; wgrouptype; wgrouptype = wgrouptype->next) {
wm_widgetgrouptype_keymap_init(wgrouptype, keyconf);
}
}
}
/** \} */ /* wmWidgetMapType */

View File

@@ -0,0 +1,167 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
* All rights reserved.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/windowmanager/widgets/wm_widget_wmapi.h
* \ingroup wm
*
* \name Widgets Window Manager API
* \brief API for usage in window manager code only.
*
* Only included in wm.h and lower level files.
*/
#ifndef __WM_WIDGET_WMAPI_H__
#define __WM_WIDGET_WMAPI_H__
struct wmEventHandler;
struct wmOperatorType;
struct wmOperator;
/* -------------------------------------------------------------------- */
/* wmWidget */
typedef void (*wmWidgetSelectFunc)(struct bContext *, struct wmWidget *, const int);
/* widgets are set per region by registering them on widgetmaps */
typedef struct wmWidget {
struct wmWidget *next, *prev;
char idname[MAX_NAME + 4]; /* + 4 for unique '.001', '.002', etc suffix */
/* pointer back to parent widget group */
struct wmWidgetGroup *wgroup;
/* could become wmWidgetType */
/* draw widget */
void (*draw)(const struct bContext *C, struct wmWidget *widget);
/* determine if the mouse intersects with the widget. The calculation should be done in the callback itself */
int (*intersect)(struct bContext *C, const struct wmEvent *event, struct wmWidget *widget);
/* determines 3d intersection by rendering the widget in a selection routine. */
void (*render_3d_intersection)(const struct bContext *C, struct wmWidget *widget, int selectionbase);
/* handler used by the widget. Usually handles interaction tied to a widget type */
int (*handler)(struct bContext *C, const struct wmEvent *event, struct wmWidget *widget, const int flag);
/* widget-specific handler to update widget attributes based on the property value */
void (*prop_data_update)(struct wmWidget *widget, int slot);
/* returns the final position which may be different from the origin, depending on the widget.
* used in calculations of scale */
void (*get_final_position)(struct wmWidget *widget, float vec[3]);
/* activate a widget state when the user clicks on it */
int (*invoke)(struct bContext *C, const struct wmEvent *event, struct wmWidget *widget);
/* called when widget tweaking is done - used to free data and reset property when cancelling */
void (*exit)(bContext *C, struct wmWidget *widget, const bool cancel);
int (*get_cursor)(struct wmWidget *widget);
/* called when widget selection state changes */
wmWidgetSelectFunc select;
int flag; /* flags set by drawing and interaction, such as highlighting */
unsigned char highlighted_part;
/* center of widget in space, 2d or 3d */
float origin[3];
/* custom offset from origin */
float offset[3];
/* runtime property, set the scale while drawing on the viewport */
float scale;
/* user defined scale, in addition to the original one */
float user_scale;
/* user defined width for line drawing */
float line_width;
/* widget colors (uses default fallbacks if not defined) */
float col[4], col_hi[4];
/* data used during interaction */
void *interaction_data;
/* name of operator to spawn when activating the widget */
const char *opname;
/* operator properties if widget spawns and controls an operator, or owner pointer if widget spawns and controls a property */
PointerRNA opptr;
/* maximum number of properties attached to the widget */
int max_prop;
/* arrays of properties attached to various widget parameters. As the widget is interacted with, those properties get updated */
PointerRNA *ptr;
PropertyRNA **props;
} wmWidget;
/* -------------------------------------------------------------------- */
/* wmWidgetGroup */
void WIDGETGROUP_OT_widget_select(struct wmOperatorType *ot);
void WIDGETGROUP_OT_widget_tweak(struct wmOperatorType *ot);
void wm_widgetgroup_attach_to_modal_handler(struct bContext *C, struct wmEventHandler *handler,
struct wmWidgetGroupType *wgrouptype, struct wmOperator *op);
/* wmWidgetGroupType->flag */
enum {
WM_WIDGETGROUPTYPE_3D = (1 << 0), /* WARNING: Don't change this! Bit used for wmWidgetMapType comparisons! */
/* widget group is attached to operator, and is only accessible as long as this runs */
WM_WIDGETGROUPTYPE_OP = (1 << 10),
WM_WIDGETGROUP_INITIALIZED = (1 << 11), /* wgroup has been initialized */
};
/* -------------------------------------------------------------------- */
/* wmWidgetMap */
void wm_widgets_keymap(struct wmKeyConfig *keyconf);
bool wm_widgetmap_is_3d(const struct wmWidgetMap *wmap);
void wm_widgetmaps_handled_modal_update(
bContext *C, struct wmEvent *event, struct wmEventHandler *handler,
const struct wmOperatorType *ot);
void wm_widgetmap_handler_context(bContext *C, struct wmEventHandler *handler);
wmWidget *wm_widgetmap_find_highlighted_3D(struct wmWidgetMap *wmap, bContext *C,
const struct wmEvent *event, unsigned char *part);
wmWidget *wm_widgetmap_find_highlighted_widget(struct wmWidgetMap *wmap, bContext *C,
const struct wmEvent *event, unsigned char *part);
void wm_widgetmap_set_highlighted_widget(struct wmWidgetMap *wmap, const bContext *C,
wmWidget *widget, unsigned char part);
wmWidget *wm_widgetmap_get_highlighted_widget(struct wmWidgetMap *wmap);
void wm_widgetmap_set_active_widget(struct wmWidgetMap *wmap, bContext *C,
const struct wmEvent *event, wmWidget *widget);
wmWidget *wm_widgetmap_get_active_widget(struct wmWidgetMap *wmap);
bool wm_widgetmap_deselect_all(struct wmWidgetMap *wmap, wmWidget ***sel);
#endif /* __WM_WIDGET_WMAPI_H__ */

View File

@@ -68,6 +68,8 @@ typedef struct wmEventHandler {
/* drop box handler */
ListBase *dropboxes;
/* widget handler */
struct wmWidgetMap *widgetmap;
} wmEventHandler;

View File

@@ -339,6 +339,8 @@ enum {
EVT_DROP = 0x5023,
EVT_BUT_CANCEL = 0x5024,
/* could become widget callback */
EVT_WIDGET_UPDATE = 0x5024,
/* ********** End of Blender internal events. ********** */
};