//===========================================================================
int varset_message(int tokencount, char *tokens[], bool from_core, module* caller)
{
    int varnameidx;
    bool is_static;
    if (tokencount == 4)
    {
        varnameidx = 2;
        is_static = false;
    }
    else if (tokencount == 5 && !strcmp(tokens[2], "Static") )
    {
        varnameidx = 3;
        is_static = true;
    }
    else
        return 1;

    int i = atoi(variables_get(tokens[varnameidx],"0", caller));
    if	(	config_set_int(tokens[varnameidx+1],&i) //Try reading it as an int
            ||	config_set_int_expr(tokens[varnameidx+1],&i) // Try calculating the string as an expression
       )
        variables_set(is_static,tokens[varnameidx],i, caller);
    else variables_set(is_static, tokens[varnameidx], tokens[varnameidx+1], caller);
    return 0;
}
LRESULT CALLBACK message_event(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static const int message_blackboxmessages[] = {BB_RECONFIGURE, BB_BROADCAST, BB_DESKCLICK, BB_DRAGTODESKTOP, BB_HIDEMENU, BB_TASKSUPDATE,BB_WORKSPACE,0};

    switch(msg)
    {
    case WM_CREATE:
        //Register the window to recieve BlackBox events
        SendMessage(plugin_hwnd_blackbox, BB_REGISTERMESSAGE, (WPARAM)hwnd, (LPARAM)message_blackboxmessages);
        break;

    case WM_DESTROY:
        //Unregister to recieve BlackBox events
        SendMessage(plugin_hwnd_blackbox, BB_UNREGISTERMESSAGE, (WPARAM)hwnd, (LPARAM)message_blackboxmessages);
        break;

    case BB_DRAGTODESKTOP:
        if (NULL == plugin_desktop_drop_command) return false;
        if (!(wParam & 1))
        {
            variables_set(false,"DroppedFile", (const char *)lParam);
            message_interpret(plugin_desktop_drop_command, false, NULL);
        }
        return true;
    case BB_TASKSUPDATE:
        controls_updatetasks();
        break;
    case BBI_POSTCOMMAND:
        SendMessage(plugin_hwnd_blackbox, BB_BROADCAST, 0, lParam);
        delete (char *)lParam;
        break;

    case BB_RECONFIGURE:
        plugin_reconfigure(false);
        break;

    case BB_DESKCLICK:
        if (lParam == 0)
            controls_clickraise();
        break;

    case BB_BROADCAST:
        message_interpret((const char *)lParam, true, NULL);
        break;

    case WM_TIMER:
        KillTimer(hwnd, wParam);
        if (1 == wParam)
            config_backup(config_path_mainscript);
        break;

    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//controltype_button_event
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LRESULT controltype_button_event(control *c, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	controltype_button_details *details = (controltype_button_details *) c->controldetails;

	switch (msg)
	{
		case WM_DROPFILES:
		{
			char buffer[MAX_PATH];
			variables_set(false, "DroppedFile", get_dragged_file(buffer, wParam));
			agent_notify(details->agents[ (details->is_twostate ? CONTROLTYPE_TWOSTATEBUTTON_AGENT_ONDROP : CONTROLTYPE_BUTTON_AGENT_ONDROP)], NOTIFY_CHANGE, NULL);
			break;
		}

		case WM_LBUTTONDOWN:
		case WM_RBUTTONDOWN:
		case WM_MBUTTONDOWN:
		case WM_LBUTTONDBLCLK:
		case WM_RBUTTONDBLCLK:
		case WM_MBUTTONDBLCLK:

			//If this is a switchbutton that is not writable, break
			if (details->is_twostate == true
				&& details->agents[CONTROLTYPE_TWOSTATEBUTTON_AGENT_VALUECHANGE] != NULL
				&& details->agents[CONTROLTYPE_TWOSTATEBUTTON_AGENT_VALUECHANGE]->writable == false)
			{
				break;
			}
			
			//Notify the agents of events
			details->pressed = details->hilite = true;
			style_draw_invalidate(c);
			if (false == details->is_twostate)
			{
				//Action button - Mouse down - TRIGGER type
				int mouse_agent = CONTROLTYPE_BUTTON_AGENT_MOUSEDOWN;
				if	( ((msg == WM_LBUTTONDOWN) || (msg == WM_LBUTTONDBLCLK)) &&
					(details->agents[CONTROLTYPE_BUTTON_AGENT_LMOUSEDOWN] != NULL))
						mouse_agent = CONTROLTYPE_BUTTON_AGENT_LMOUSEDOWN;
				else
				if	( ((msg == WM_RBUTTONDOWN) || (msg == WM_RBUTTONDBLCLK)) &&
					(details->agents[CONTROLTYPE_BUTTON_AGENT_RMOUSEDOWN] != NULL))
						mouse_agent = CONTROLTYPE_BUTTON_AGENT_RMOUSEDOWN;
				else
				if	( ((msg == WM_MBUTTONDOWN) || (msg == WM_MBUTTONDBLCLK)) &&
					(details->agents[CONTROLTYPE_BUTTON_AGENT_MMOUSEDOWN] != NULL))
						mouse_agent = CONTROLTYPE_BUTTON_AGENT_MMOUSEDOWN;

				agent_notify(details->agents[mouse_agent], NOTIFY_CHANGE, NULL);
			}
			break;

		case WM_KILLFOCUS:
		case WM_LBUTTONUP:
		case WM_RBUTTONUP:
		case WM_MBUTTONUP:

			//If this is a switchbutton that is not writable, break
			if (details->is_twostate == true
				&& details->agents[CONTROLTYPE_TWOSTATEBUTTON_AGENT_VALUECHANGE] != NULL
				&& details->agents[CONTROLTYPE_TWOSTATEBUTTON_AGENT_VALUECHANGE]->writable == false)
			{
				break;
			}

			if (details->pressed)
			{
				bool trigger = details->hilite;
				details->pressed = details->hilite = false;
				style_draw_invalidate(c);
				if (trigger)
				{
					//Notify the agents of events
					if (details->is_twostate)
					{
						details->is_on = false == details->is_on;
						//Value change - BOOL type
						agent_notify(details->agents[CONTROLTYPE_TWOSTATEBUTTON_AGENT_VALUECHANGE], NOTIFY_CHANGE, (void *) &details->is_on);
						//Pressed/Unpressed - TRIGGER type
						agent_notify(details->agents[(details->is_on ? CONTROLTYPE_TWOSTATEBUTTON_AGENT_PRESSED : CONTROLTYPE_TWOSTATEBUTTON_AGENT_UNPRESSED)], NOTIFY_CHANGE, NULL);
					}
					else
					{
						//Action button - Mouse up - TRIGGER type
						int mouse_agent = CONTROLTYPE_BUTTON_AGENT_MOUSEUP;
						if ( (msg == WM_LBUTTONUP) && (details->agents[CONTROLTYPE_BUTTON_AGENT_LMOUSEUP] != NULL)) mouse_agent = CONTROLTYPE_BUTTON_AGENT_LMOUSEUP;
						else if ( (msg == WM_RBUTTONUP) && (details->agents[CONTROLTYPE_BUTTON_AGENT_RMOUSEUP] != NULL)) mouse_agent = CONTROLTYPE_BUTTON_AGENT_RMOUSEUP;
						else if ( (msg == WM_MBUTTONUP) && (details->agents[CONTROLTYPE_BUTTON_AGENT_MMOUSEUP] != NULL)) mouse_agent = CONTROLTYPE_BUTTON_AGENT_MMOUSEUP;

						agent_notify(details->agents[mouse_agent], NOTIFY_CHANGE, NULL);

					}
				}
			}
			break;

		case WM_MOUSEMOVE:
			if (details->pressed)
			{
				RECT r; GetClientRect(hwnd, &r);
				POINT pt;
				pt.x = (short)LOWORD(lParam);
				pt.y = (short)HIWORD(lParam);
				bool over = PtInRect(&r, pt);
				if (over != details->hilite)
				{
					details->hilite = over;
					style_draw_invalidate(c);
				}
			}
			break;

		case WM_PAINT:
			styledrawinfo d;

			//Begin drawing
			if (style_draw_begin(c, d))
			{
				//Paint background according to the current style on the bitmap ...
				int style_index = STYLETYPE_NONE;
				switch (c->windowptr->style)
				{
				case STYLETYPE_TOOLBAR:
					style_index = (details->hilite || details->is_on) ? STYLETYPE_INSET : STYLETYPE_TOOLBAR; break;
				case STYLETYPE_INSET:
					style_index = (details->hilite || details->is_on) ? STYLETYPE_TOOLBAR : STYLETYPE_INSET; break;
				case STYLETYPE_FLAT:
					style_index = (details->hilite || details->is_on) ? STYLETYPE_SUNKEN : STYLETYPE_FLAT; break;
				case STYLETYPE_SUNKEN:
					style_index = (details->hilite || details->is_on) ? STYLETYPE_FLAT : STYLETYPE_SUNKEN; break;
				}
				
				if (c->windowptr->has_custom_style)
				{
					if (details->hilite || details->is_on)
						style_draw_box(
							d.rect,
							d.buffer,
							STYLETYPE_INSET,
							c->windowptr->is_bordered
						);
					else
						style_draw_box(
							d.rect,
							d.buffer,
							c->windowptr->styleptr,
							c->windowptr->is_bordered
						);

				}
				else
				style_draw_box(
					d.rect,
					d.buffer,
					style_index,
					c->windowptr->is_bordered
					);
				
				//Draw the image, dependant on state and availability of second image
				if (details->agents[CONTROLTYPE_BUTTON_IMAGE_WHENPRESSED] && (details->hilite || details->is_on))
				{
					d.apply_sat_hue = false == (details->hilite || details->is_on);
					agent_notify(details->agents[CONTROLTYPE_BUTTON_IMAGE_WHENPRESSED], NOTIFY_DRAW, &d);
				}
				else if (details->agents[CONTROLTYPE_BUTTON_IMAGE])
				{
					d.apply_sat_hue = false == (details->hilite || details->is_on);
					agent_notify(details->agents[CONTROLTYPE_BUTTON_IMAGE], NOTIFY_DRAW, &d);
				}

				//Draw the caption
				if (details->caption)
				{
					int vpad = style_bevel_width + 1;
					if (c->windowptr->is_bordered) vpad += style_border_width;
					if (vpad < 2) vpad = 2;

					int hpad = vpad;
					if (0 == (details->settings & DT_CENTER)) hpad += 1;
					d.rect.left  += hpad;
					d.rect.right -= hpad;

					if (!(details->settings & DT_VCENTER))
					{
						d.rect.top += vpad;
						d.rect.bottom -= vpad;
					}
					if (c->windowptr->has_custom_style)
						if (details->hilite || details->is_on)
						style_draw_text(
							d.rect,
							d.buffer,
							STYLETYPE_INSET,
							details->caption,
							details->settings,
							plugin_enableshadows
							);
						else
						style_draw_text(
							d.rect,
							d.buffer,
							c->windowptr->styleptr,
							details->caption,
							details->settings,
							plugin_enableshadows
							);
					else
					style_draw_text(
						d.rect,
						d.buffer,
						style_index,
						details->caption,
						details->settings,
						plugin_enableshadows
						);
				}
			}
			//End drawing
			style_draw_end(d);
			break;

	}

	return 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//controltype_label_message
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int controltype_label_message(control *c, int tokencount, char *tokens[])
{
	// token strings

	enum
	{
		T_NONE          = 0,
		T_STYLE         ,
		T_VALIGN        ,
		T_HALIGN        ,
		T_HASTITLE      ,
		T_LOCKPOS       ,

		T_PLUGINLOAD    ,
		T_PLUGINUNLOAD  ,
		T_PLUGINSETPOS  ,
		T_PLUGINSHOW    ,

		T_PLUGINABOUT
	};

	extern char szWPStyle [];

	static struct token_check controltype_label_property_tokens[] =
	{
		{ szWPStyle,            T_STYLE         , 1 },
		{ "VAlign",             T_VALIGN        , 1 },
		{ "HAlign",             T_HALIGN        , 1 },
		{ "HasTitleBar",        T_HASTITLE      , 1 },
		{ "IsLocked",           T_LOCKPOS       , 1 },
		{ NULL }
	};

	static struct token_check controltype_label_plugin_property_tokens[] =
	{
		{ "IsVisible",          T_PLUGINSHOW    , 1 },
		{ "Position",           T_PLUGINSETPOS  , 2 },
		{ NULL }
	};

	static struct token_check controltype_label_plugin_tokens[] =
	{
		{ "Load",               T_PLUGINLOAD    , 1 },
		{ "Unload",             T_PLUGINUNLOAD  , 1 },
		{ "About",              T_PLUGINABOUT   , 0 },
		{ szBActionPluginSetProperty, (UINT_PTR)controltype_label_plugin_property_tokens  , 2 },
		{ NULL }
	};

	static struct token_check controltype_label_message_tokens[] =
	{
		{ szBActionSetControlProperty, (UINT_PTR)controltype_label_property_tokens, 2 },
		{ szBActionPlugin, (UINT_PTR)controltype_label_plugin_tokens, 2 },
		{ NULL }
	};

	// -----------------
	//Get the details
	controltype_label_details *details = (controltype_label_details *) c->controldetails;

	//If set control details
	int i;
	int curtok = 2;
	switch (token_check(controltype_label_message_tokens, &curtok, tokencount, tokens))
	{
		// -----------------
	case T_STYLE:
		if (-1 != (i = get_string_index(tokens[curtok], szStyleNames)))
		{
			c->windowptr->style = i;
			style_draw_invalidate(c);
			return 0;
		}
		break;

		// -----------------
	case T_HALIGN:
		if (-1 != (i = get_string_index(tokens[curtok], label_haligns)))
		{
			details->halign = i;
			controltype_label_updatesettings(details);
			style_draw_invalidate(c);
			return 0;
		}
		break;

		// -----------------
	case T_VALIGN:
		if (-1 != (i = get_string_index(tokens[curtok], label_valigns)))
		{
			details->valign = i;
			controltype_label_updatesettings(details);
			style_draw_invalidate(c);
			return 0;
		}
		break;

		// -----------------
	case T_HASTITLE:
		if (details->is_frame && config_set_bool(tokens[curtok], &details->has_titlebar))
		{
			style_draw_invalidate(c);
			return 0;
		}
		break;

		// -----------------
	case T_LOCKPOS:
		if (details->is_frame && config_set_bool(tokens[curtok], &details->is_locked))
			return 0;
		break;

		// -----------------
	case T_PLUGINLOAD:
		if (details->is_frame)
		{
			char *plugin_name = tokens[curtok];
			if (0 == strcmp(plugin_name, "*browse*"))
			{
				// "open file" dialog
				plugin_name = dialog_file("Plugins\0*.dll\0", "Add Plugin" , NULL, ".dll", false);
				if (NULL == plugin_name)
				{
					//message_override = true;
					return 2;
				}
			}
			ModuleInfo * m = loadPlugin(&details->module_info, c->windowptr->hwnd, plugin_name);
			if (m)
			{
				variables_set(false, "LastPlugin", m->module_name);
				return 0;
			}
		}
		break;

		// -----------------
	case T_PLUGINUNLOAD:
		if (unloadPlugin(&details->module_info, tokens[curtok]))
			return 0;
		break;

		// -----------------
	case T_PLUGINSETPOS:
	{
		int x, y;
		if (config_set_int(tokens[curtok], &x)
				&& config_set_int(tokens[1+curtok], &y)
				&& plugin_setpos(details->plugin_info, tokens[-2+curtok], x, y)
		   )
			return 0;

		return 0; // dont generate an error here...
	}
	break;

	// -----------------
	case T_PLUGINSHOW:
	{
		bool show;
		if (plugin_getset_show_state(details->plugin_info, tokens[-2+curtok],
									 config_set_bool(tokens[curtok], &show) ? show : 2)
		   )
			return 0;

		return 0; // dont generate an error here...
	}
	break;

	// -----------------
	case T_PLUGINABOUT:
	{
		aboutPlugins(details->module_info, c->controlname);
		return 0;
	}
	break;

	// -----------------
	//Must be an agent message
	default:
		return agent_controlmessage(c, tokencount, tokens, CONTROLTYPE_LABEL_AGENT_COUNT, details->agents, controltype_label_agentnames, controltype_label_agenttypes);
	}
	return 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//controltype_label_event
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LRESULT controltype_label_event(control *c, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	controltype_label_details *details = (controltype_label_details *) c->controldetails;

	switch (msg)
	{
	case WM_DROPFILES:
	{
		char buffer[MAX_PATH];
		variables_set(false, "DroppedFile", get_dragged_file(buffer, wParam));
		agent_notify(details->agents[CONTROLTYPE_LABEL_AGENT_ONDROP], NOTIFY_CHANGE, NULL);
		break;
	}

	case WM_PAINT:
		styledrawinfo d;

		//Begin drawing
		if (style_draw_begin(c, d))
		{
			//Paint background according to the current style on the bitmap ...
			if (c->windowptr->has_custom_style)
				style_draw_box(
					d.rect,
					d.buffer,
					c->windowptr->styleptr,
					c->windowptr->is_bordered
				);
			else
				style_draw_box(
					d.rect,
					d.buffer,
					c->windowptr->style,
					c->windowptr->is_bordered
				);

			//Draw the title bar
			if (details->has_titlebar)
			{
				RECT titlebar = d.rect;
				int b = d.rect.top+FRAME_TITLEBAR_HEIGHT;
				titlebar.bottom = b < d.rect.bottom ? b : d.rect.bottom;
				style_draw_box(titlebar, d.buffer, STYLETYPE_TOOLBAR, c->windowptr->is_bordered);
			}

			//Draw the image
			if (details->agents[CONTROLTYPE_LABEL_AGENT_IMAGE])
			{
				agent_notify(details->agents[CONTROLTYPE_LABEL_AGENT_IMAGE], NOTIFY_DRAW, &d);
			}

			//Draw the caption
			if (details->caption)
			{
				int vpad = style_bevel_width + 1;
				if (c->windowptr->is_bordered) vpad += style_border_width;
				if (vpad < 2) vpad = 2;

				int hpad = vpad;
				if (0 == (details->settings & DT_CENTER)) hpad += 1;
				d.rect.left  += hpad;
				d.rect.right -= hpad;

				if (!(details->settings & DT_VCENTER))
				{
					if (details->has_titlebar)
						d.rect.top += (FRAME_TITLEBAR_HEIGHT-style_font_height)/2;
					else
						d.rect.top += vpad;

					d.rect.bottom -= vpad;
				}
				else
				{
					if (details->has_titlebar)
						d.rect.top += FRAME_TITLEBAR_HEIGHT;
				}

				if (c->windowptr->has_custom_style)
					style_draw_text(
						d.rect,
						d.buffer,
						c->windowptr->styleptr,
						details->caption,
						details->settings,
						plugin_enableshadows
					);
				else
					style_draw_text(
						d.rect,
						d.buffer,
						c->windowptr->style,
						details->caption,
						details->settings,
						plugin_enableshadows
					);
			}
		}
		//End drawing
		style_draw_end(d);
		break;

	case WM_RBUTTONUP:
	case WM_NCRBUTTONUP:
		agent_notify(details->agents[CONTROLTYPE_LABEL_AGENT_RIGHTMOUSEUP], NOTIFY_CHANGE, NULL);
		break;

	case SLIT_ADD:
	case SLIT_REMOVE:
	case SLIT_UPDATE:
		SlitWndProc(c, hwnd, msg, wParam, lParam);
		break;

	}
	return 0;
}