/***************************************************************************

  CWidget.h

  (c) 2000-2017 Benoît Minisini <benoit.minisini@gambas-basic.org>

  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, 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.

***************************************************************************/

#ifndef __CWIDGET_H
#define __CWIDGET_H

#include "main.h"
#include "share/gb.form.properties.h"

#include <QObject>
#include <QWidget>
#include <QIcon>
#include <QPixmap>
#include <QEvent>
#include <QHash>

typedef
	struct {
		GB_COLOR fg;
		GB_COLOR bg;
		GB_VARIANT_VALUE tag;
		void *cursor;
		char *popup;
		void *proxy;
		void *proxy_for;
		char *action;
		void *container_for;
		short wheel_x;
		short wheel_y;
		char mouse;
	}
	CWIDGET_EXT;
	
typedef
	struct {
		GB_COLOR fg;
		GB_COLOR bg;
		void *cursor;
		char mouse;
		//unsigned drop : 1;
		unsigned no_tab_focus : 1;
		unsigned tracking : 1;
	}
	CWIDGET_PROXY;

typedef
	struct CWIDGET {
		GB_BASE ob;
		QWidget *widget;
		void *ext;
		struct {
			unsigned deleted : 1;
			unsigned scrollview : 1;           // inherits QScrollView
			unsigned expand : 1;               //
			unsigned ignore : 1;               //
			unsigned visible : 1;              //
			unsigned autoFillBackground : 1;
			unsigned fillBackground : 1;       //
			unsigned noBackground : 1;         //

			unsigned shown : 1;                // for containers
			unsigned tracking : 1;
			unsigned old_tracking : 1;
			unsigned grab : 1;
			unsigned dragging: 1;              //
			unsigned no_tab_focus : 1;
			unsigned inside : 1;               //

			unsigned inside_later : 1;
			unsigned use_tablet : 1;           //
			unsigned has_action : 1;
			unsigned drop : 1;
			unsigned resized : 1;
			unsigned wheel : 1;                // eat wheel events
			unsigned design : 1;               //
			unsigned design_ignore : 1;        //

			unsigned no_design : 1;
			unsigned orientation : 1;          // for scrollbars & similar widgets
			unsigned inverted : 1;             // if layout has been inverted
			unsigned direction : 2;            // text direction
			unsigned user : 1;                 // UserControl or UserContainer
			unsigned no_animation : 1;         // enable or disable animations explicitly
			unsigned _reserved : 1;
			} flag;
		char *name;
		void *font;
		uint key;
		}
	CWIDGET; // BEWARE: gb.qt.h MUST be updated accordingly!

typedef
	CWIDGET CCONTROL;

typedef
	struct {
		CWIDGET widget;
		QWidget *container;
		unsigned mode : 4;
		unsigned locked : 1;
		unsigned dirty : 1;
		unsigned margin : 1;
		unsigned spacing : 1;
		unsigned padding : 8;
		unsigned indent : 1;
		unsigned centered : 1;
		unsigned autoresize : 1;
		unsigned invert : 1;
		unsigned _reserved: 12;
		}
	CCONTAINER_ARRANGEMENT;

typedef
	struct {
		CWIDGET widget;
		QWidget *container;
		int32_t arrangement;
		}
	CCONTAINER;

#ifndef __CWIDGET_CPP

extern GB_DESC CControlDesc[];
extern CWIDGET *CWIDGET_active_control;
extern CWIDGET *CWIDGET_previous_control;
extern CWIDGET *CWIDGET_hovered;

extern int CCONTROL_last_event_type;

#else

#define THIS (((CWIDGET *)_object))
#define THIS_EXT ((CWIDGET_EXT *)((CWIDGET *)_object)->ext)
#define WIDGET QWIDGET(_object)

#endif

#define QWIDGET(object) (((CWIDGET *)object)->widget)
#define QCONTAINER(_ob) CWidget::getContainerWidget((CCONTAINER *)_ob)

DECLARE_METHOD(Control_Delete);
DECLARE_METHOD(Control_Refresh);
DECLARE_PROPERTY(Control_Tag);
DECLARE_PROPERTY(CWIDGET_border_full);
DECLARE_PROPERTY(CWIDGET_border_simple);
DECLARE_PROPERTY(CWIDGET_scrollbar);
DECLARE_PROPERTY(Control_Background);
DECLARE_PROPERTY(Control_Design);
DECLARE_PROPERTY(Control_Enabled);
DECLARE_PROPERTY(Control_Font);
DECLARE_PROPERTY(Control_Action);
DECLARE_PROPERTY(Control_Mouse);

#define RAISE_EVENT(_event) \
{ \
	GET_SENDER(); \
\
	if (_object == NULL) \
		return; \
\
	GB.Raise(_object, _event, 0); \
}

#define RAISE_EVENT_ACTION(_event) \
{ \
	GET_SENDER(); \
\
	if (_object == NULL) \
		return; \
\
	CWIDGET_raise_event_action(_object, _event); \
}


/*#define ALIGN_MASK (Qt::AlignLeft | Qt::AlignRight | Qt::AlignTop | Qt::AlignBottom | Qt::AlignCenter)
#define ALIGN_HMASK (Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter)
#define ALIGN_VMASK (Qt::AlignTop | Qt::Bottom | Qt::AlignVCenter)*/

#define ALIGN_HMASK (Qt::AlignHorizontal_Mask)
#define ALIGN_VMASK (Qt::AlignVertical_Mask)
#define ALIGN_MASK (ALIGN_HMASK | ALIGN_VMASK)

#define SET_WIDGET(_ob, _wid) (((CWIDGET *)_ob)->widget = (_wid))
#define CLEAR_WIDGET(_ob) SET_WIDGET(_ob, 0)

#define EMBED_WAIT   0
#define EMBED_OK     1
#define EMBED_ERROR  2

void CWIDGET_new(QWidget *w, void *_object, bool no_show = false);
void CWIDGET_init_name(CWIDGET *_object);
void CWIDGET_set_name(CWIDGET *_object, const char *name);
#define CWIDGET_get_name(_object) (((CWIDGET *)_object)->name)
int CWIDGET_check(void *object);

QString CWIDGET_Utf8ToQString(GB_STRING *str);

void CWIDGET_destroy(CWIDGET *_object);

QSize CWIDGET_iconset(QIcon &icon, const QPixmap &p, int size = 0);

void CWIDGET_set_color(CWIDGET *_object, int bg, int fg, bool handle_proxy = false);
void CWIDGET_reset_color(CWIDGET *_object);
QT_COLOR_FUNC CWIDGET_after_set_color(QT_COLOR_FUNC func);
GB_COLOR CWIDGET_get_background(CWIDGET *_object, bool handle_proxy = false);
GB_COLOR CWIDGET_get_foreground(CWIDGET *_object, bool handle_proxy = false);
GB_COLOR CWIDGET_get_real_background(CWIDGET *_object);
GB_COLOR CWIDGET_get_real_foreground(CWIDGET *_object);

void *CWIDGET_get_real_font(CWIDGET *_object);

void *CWIDGET_get_parent(void *_object);
uintptr_t CWIDGET_get_handle(void *_object);
bool CWIDGET_is_visible(void *_object);
void CWIDGET_set_visible(CWIDGET *_object, bool v);

void CWIDGET_grab(CWIDGET *_object);

void CWIDGET_move(void *_object, int x, int y);
void CWIDGET_resize(void *_object, int w, int h);
void CWIDGET_move_resize(void *_object, int x, int y, int w, int h);
void CWIDGET_auto_resize(void *_object, int w, int h);

void CWIDGET_handle_focus(CWIDGET *control, bool on);
void CWIDGET_finish_focus(void);

void CWIDGET_register_proxy(void *_object, void *proxy);
bool CWIDGET_container_for(void *_object, void *container_for);

#ifdef QT5
#define CWIDGET_enter_popup() ((void *)NULL)
void CWIDGET_leave_popup(void *);
#else
void *CWIDGET_enter_popup();
void CWIDGET_leave_popup(void *save);
#endif

void CACTION_register(void *control, const char *old, const char *key);
void CACTION_raise(void *control);
void CWIDGET_raise_event_action(void *control, int event);

bool CWIDGET_get_allow_focus(void *_object);
void CWIDGET_set_allow_focus(void *_object, bool f);

bool CWIDGET_is_design(void *_object);

void CWIDGET_check_visibility(CWIDGET *_object);
void CWIDGET_check_hovered();

void CWIDGET_set_design(CWIDGET *_object, bool ignore = false);

void CWIDGET_set_inverted(void *_object, bool v);

void *CWIDGET_get_next_previous(void *_object, bool next);
void CWIDGET_set_focus(void *_object);
void *CWIDGET_get_next_focus(void *_object);
void *CWIDGET_get_previous_focus(void *_object);
bool CWIDGET_has_no_tab_focus(void *_object);

CWIDGET_PROXY *CWIDGET_save_proxy(void *_object);
void CWIDGET_apply_proxy(CWIDGET_PROXY *data, void *_object);

#ifndef DO_NOT_DECLARE_EVENTS
#ifndef __CWIDGET_CPP
extern
#endif
int
EVENT_MouseDown,
EVENT_MouseUp,
EVENT_MouseMove,
EVENT_MouseDrag,
EVENT_MouseWheel,
EVENT_DblClick,
EVENT_KeyPress,
EVENT_KeyRelease,
EVENT_Enter,
EVENT_Leave,
EVENT_GotFocus,
EVENT_LostFocus,
EVENT_Menu,
EVENT_Drag,
EVENT_DragMove,
EVENT_Drop,
EVENT_DragLeave;
#endif

struct CWINDOW;

class CWidget : public QObject
{
	Q_OBJECT

public:

	static CWidget manager;

	static void add(QObject *, void *);
	static CWIDGET *get(QObject *);
	static CWIDGET *getReal(QObject *o) { return dict[o]; }
	static CWIDGET *getRealExisting(QObject *);
	static CWIDGET *getDesign(QObject *);

	static QWidget *getContainerWidget(CCONTAINER *object);

	static CWINDOW *getWindow(CWIDGET *object);
	static CWINDOW *getTopLevel(CWIDGET *object);
	
	static void each(void (*func)(CWIDGET *));

	//static void setName(CWIDGET *, const char *);
	//static void installFilter(QObject *);
	//static void removeFilter(QObject *);

	//static const char *getProperties(const void *klass);
	//static void setProperties(const void *klass, const char *prop);

	static void removeFocusPolicy(QWidget *);

public slots:

	void destroy(void);

protected:

	bool eventFilter(QObject *, QEvent *);

private:

	static bool real;
	static QHash<QObject *, CWIDGET *> dict;
};

#endif
