which included commits to RCS files with non-trunk default branches. git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@14 e016b1c5-ed68-44aa-a2f7-31cac88cffde
481 lines
13 KiB
C++
Executable File
481 lines
13 KiB
C++
Executable File
/*
|
|
* Frame control for the MESGUI library
|
|
* Copyright (C) 2002 Eric Maxey <[email protected]>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "control_common.h"
|
|
|
|
/****************************
|
|
ggFrame
|
|
****************************/
|
|
|
|
ggFrame::ggFrame() : ggControl()
|
|
{
|
|
focus=NULL;
|
|
flags |= GGFLAG_DONT_DRAW_TITLE | GGFLAG_FOCUSABLE | GGFLAG_FRAME;
|
|
mousedowncontrol=NULL;
|
|
dragstate=0;
|
|
r=0.2f;
|
|
g=0.7f;
|
|
b=1.0f;
|
|
a=0.4f;
|
|
framer=1.0f;
|
|
frameg=0.0f;
|
|
frameb=0.0f;
|
|
framea=0.7f;
|
|
scale=1;
|
|
offsetx=0;
|
|
offsety=0;
|
|
scrollbutton=NULL;
|
|
passbackfunc=NULL;
|
|
drawFunc=NULL;
|
|
}
|
|
|
|
ggFrame::ggFrame(const char *t) : ggControl()
|
|
{
|
|
*stringValP = t;
|
|
focus=NULL;
|
|
flags |= GGFLAG_FOCUSABLE | GGFLAG_MOVABLE | GGFLAG_FRAME;
|
|
mousedowncontrol=NULL;
|
|
dragstate=0;
|
|
r=0.2f;
|
|
g=0.7f;
|
|
b=1.0f;
|
|
framer=1.0f;
|
|
frameg=0.0f;
|
|
frameb=0.0f;
|
|
framea=0.5f;
|
|
scale=1;
|
|
offsetx=0;
|
|
offsety=0;
|
|
scrollbutton=NULL;
|
|
passbackfunc=NULL;
|
|
drawFunc=NULL;
|
|
}
|
|
|
|
ggFrame::~ggFrame()
|
|
{
|
|
for (int i=0; i<controls.size(); i++)
|
|
delete controls[i];
|
|
}
|
|
|
|
void ggFrame::Draw()
|
|
{
|
|
if (!(flags & GGFLAG_DONT_DRAW_BORDER)) {
|
|
if (!(flags & GGFLAG_DONT_DRAW_TITLE)) {
|
|
glBegin(GL_QUADS);
|
|
glColor4f(framer,frameg,frameb,framea);
|
|
glVertex2d(x ,y+COL_HEIGHT);
|
|
glVertex2d(x+xsize,y+COL_HEIGHT);
|
|
glVertex2d(x+xsize,y+ysize);
|
|
glVertex2d(x ,y+ysize);
|
|
float mul = (flags & GGFLAG_FOCUSED) ? 0.7f : 1.0f;
|
|
glColor4f(r*0.6f*mul,g*0.6f*mul,b*0.6f*mul,a); glVertex2d(x ,y);
|
|
glColor4f(r*0.9f*mul,g*0.9f*mul,b*0.9f*mul,a); glVertex2d(x+xsize,y);
|
|
glColor4f(r*1.0f*mul,g*1.0f*mul,b*1.0f*mul,a); glVertex2d(x+xsize,y+COL_HEIGHT);
|
|
glColor4f(r*0.7f*mul,g*0.7f*mul,b*0.7f*mul,a); glVertex2d(x ,y+COL_HEIGHT);
|
|
glEnd();
|
|
glColor4f(1,1,1,a);
|
|
glBegin(GL_LINES);
|
|
glVertex2d(x ,y );
|
|
glVertex2d(x+xsize,y );
|
|
glVertex2d(x+xsize,y );
|
|
glVertex2d(x+xsize,y+ysize);
|
|
glVertex2d(x+xsize,y+ysize);
|
|
glVertex2d(x ,y+ysize);
|
|
glVertex2d(x ,y+ysize);
|
|
glVertex2d(x ,y-1 );
|
|
glVertex2d(x ,y+COL_HEIGHT);
|
|
glVertex2d(x+xsize,y+COL_HEIGHT);
|
|
glEnd();
|
|
fontprint(x+TO_X,y+TO_Y,stringValP->c_str());
|
|
} else {
|
|
glBegin(GL_QUADS);
|
|
glColor4f(framer,frameg,frameb,framea);
|
|
glVertex2d(x ,y);
|
|
glVertex2d(x+xsize,y);
|
|
glVertex2d(x+xsize,y+ysize);
|
|
glVertex2d(x ,y+ysize);
|
|
glEnd();
|
|
glColor4f(1,1,1,a);
|
|
glBegin(GL_LINES);
|
|
glVertex2d(x ,y );
|
|
glVertex2d(x+xsize,y );
|
|
glVertex2d(x+xsize,y );
|
|
glVertex2d(x+xsize,y+ysize);
|
|
glVertex2d(x+xsize,y+ysize);
|
|
glVertex2d(x ,y+ysize);
|
|
glVertex2d(x ,y+ysize);
|
|
glVertex2d(x ,y-1 );
|
|
glEnd();
|
|
}
|
|
}
|
|
glPushMatrix();
|
|
if (!(flags & GGFLAG_DONT_DRAW_TITLE)) {
|
|
// add a COL_HEIGHT if there's a title
|
|
glTranslated(x+offsetx,y+offsety+COL_HEIGHT,0);
|
|
} else {
|
|
glTranslated(x+offsetx,y+offsety,0);
|
|
}
|
|
if (scale!=1)
|
|
glScalef(scale,scale,1);
|
|
|
|
#define GRIDSIZE 10
|
|
if (flags & GGFLAG_DRAWGRID) {
|
|
int xl,yl,xs,ys;
|
|
xs = xsize / GRIDSIZE;
|
|
ys = ysize / GRIDSIZE;
|
|
glColor4f(0.3f,0.3f,0.3f,1.0f);
|
|
glBegin(GL_LINES);
|
|
for (xl=0; xl<xs; xl++) {
|
|
glVertex2d(x+xl*GRIDSIZE,y);
|
|
glVertex2d(x+xl*GRIDSIZE,y+ysize);
|
|
}
|
|
for (yl=0; yl<ys; yl++) {
|
|
glVertex2d(x, y+yl*GRIDSIZE);
|
|
glVertex2d(x+xsize,y+yl*GRIDSIZE);
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
for (int i=0; i<controls.size(); i++)
|
|
controls[i]->Draw();
|
|
|
|
if (drawFunc) drawFunc();
|
|
|
|
glPopMatrix();
|
|
}
|
|
|
|
void ggFrame::Message(int msg,int arg1,int arg2,int arg3,int arg4)
|
|
{
|
|
// must take care of these, even if BaseMessage does too.
|
|
if (msg==GGMSG_GAINFOCUS) focusedframe = this;
|
|
if (msg==GGMSG_LOSEFOCUS) {
|
|
if (focus) focus->Message(GGMSG_LOSEFOCUS,0,0,0,0); // tell the focused control in here, to lose focus also
|
|
if (parent) focusedframe = parent;
|
|
}
|
|
|
|
BaseMessage(msg,arg1,arg2,arg3,arg4);
|
|
|
|
switch (msg)
|
|
{
|
|
case GGMSG_KEYDOWN:
|
|
case GGMSG_KEYUP:
|
|
case GGMSG_SKEYDOWN:
|
|
case GGMSG_SKEYUP:
|
|
if (focus) focus->Message(msg,arg1,arg2,arg3,arg4);
|
|
return;
|
|
case GGMSG_MOUSEBUTTON:
|
|
// callback stuff (PassBackNextMouseClick) only if not on a control while pressing down
|
|
if (flags & GGFLAG_PASSBACK && (arg2==STATE_RELEASED || !FindControl(arg3,arg4))) {
|
|
flags &= ~GGFLAG_PASSBACK;
|
|
if (passbackfunc) passbackfunc(arg3,arg4,arg1,arg2);
|
|
if (arg2!=STATE_RELEASED) return;
|
|
}
|
|
|
|
if (arg1 != LEFT_BUTTON) return; // I only want LMB clicks for now.
|
|
|
|
arg3 -= x; // set it to be relative to the frame
|
|
arg4 -= y;
|
|
if (!(flags & GGFLAG_DONT_DRAW_BORDER)) arg4 -= COL_HEIGHT; // add a COL_HEIGHT, if there's a title.
|
|
|
|
if (arg2==STATE_RELEASED) {
|
|
if (mousedowncontrol) {
|
|
if (dragstate==1) {
|
|
mousedowncontrol->Message(GGMSG_CLICKED,0,0,arg3,arg4);
|
|
if (focus) focus->Message(GGMSG_LOSEFOCUS,0,0,0,0);
|
|
mousedowncontrol->Message(GGMSG_GAINFOCUS,0,0,0,0);
|
|
} else if (dragstate==0) {
|
|
mousedowncontrol->Message(msg,arg1,arg2,arg3,arg4);
|
|
}
|
|
mousedowncontrol->Message(GGMSG_UP,0,0,arg3,arg4);
|
|
mousedowncontrol=NULL;
|
|
} else {
|
|
// pass message to a callback func that API-user specifies
|
|
if (this == mainframe && InputCallbackFunc) InputCallbackFunc(msg,arg1,arg2,arg3,arg4);
|
|
// selection box (maybe later)
|
|
}
|
|
dragstate=0;
|
|
return;
|
|
} else { // STATE_PRESSED
|
|
ggControl *mouseover = FindControl(arg3,arg4);
|
|
if (mouseover) {
|
|
mousedowncontrol = mouseover;
|
|
mousedowncontrol->Message(GGMSG_DOWN,0,0,arg3,arg4);
|
|
|
|
// only drag a frame, if the mouse isn't on a control
|
|
bool on_control=false;
|
|
if (mouseover->flags&GGFLAG_FRAME) {
|
|
float rel_x = arg3-mouseover->x;
|
|
float rel_y = arg4-mouseover->y;
|
|
if (!(mouseover->flags & GGFLAG_DONT_DRAW_BORDER)) rel_y -= COL_HEIGHT; // add a COL_HEIGHT, if there's a title.
|
|
on_control = !((ggFrame*)mouseover)->FindControl(rel_x,rel_y)?true:false;
|
|
}
|
|
|
|
// new code
|
|
/*
|
|
//not on a control AND we are over a focused frame..
|
|
if(!on_control && mouseover == focus)
|
|
{
|
|
if (arg1 == LEFT_BUTTON) //begin frame-drag..
|
|
{
|
|
dragstate=1;
|
|
dragx = arg3;
|
|
dragy = arg4;
|
|
}
|
|
}
|
|
|
|
//not on a control or we are over the frame with focus.
|
|
if(!on_control || mouseover == focus)
|
|
{
|
|
if(mouseover != focus)
|
|
{
|
|
if(focus) //unfocus whatever has focus
|
|
focus->Message(GGMSG_LOSEFOCUS,0,0,0,0);
|
|
|
|
//give focus to whatever is under the mouse
|
|
mouseover->Message(GGMSG_GAINFOCUS,0,0,0,0);
|
|
|
|
//begin frame-drag for when the frame is already selected
|
|
if (arg1 == LEFT_BUTTON)
|
|
{
|
|
dragstate=1;
|
|
dragx = arg3;
|
|
dragy = arg4;
|
|
}
|
|
}
|
|
//forward the message to whatever was under the mouse
|
|
mouseover->Message(msg,arg1,arg2,arg3,arg4);
|
|
}
|
|
*/
|
|
if (!on_control || mouseover == focus) { // give it the message, if it's focused
|
|
if (focus) focus->Message(GGMSG_LOSEFOCUS,0,0,0,0);
|
|
mouseover->Message(GGMSG_GAINFOCUS,0,0,0,0);
|
|
mouseover->Message(msg,arg1,arg2,arg3,arg4);
|
|
} else {
|
|
if (arg1 == LEFT_BUTTON) {
|
|
dragstate=1;
|
|
dragx = arg3;
|
|
dragy = arg4;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
if (focus) focus->Message(GGMSG_LOSEFOCUS,0,0,0,0);
|
|
// pass message to a callback func that programmer specifies
|
|
if (this == mainframe && InputCallbackFunc) InputCallbackFunc(msg,arg1,arg2,arg3,arg4);
|
|
// selection box (maybe later)
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case GGMSG_MOUSEMOTION:
|
|
arg3 -= x; // set it to be relative to the frame
|
|
arg4 -= y;
|
|
if (!(flags & GGFLAG_DONT_DRAW_BORDER)) arg4 -= COL_HEIGHT; // add a COL_HEIGHT, if there's a title.
|
|
|
|
if (!mousedowncontrol) {
|
|
// mouseover events
|
|
if (this == mainframe) {
|
|
static ggControl *mouseover=NULL;
|
|
if (mouseover) mouseover->flags &= ~GGFLAG_MOUSEOVER;
|
|
mouseover=FindControl(arg3,arg4);
|
|
if (mouseover) mouseover->flags |= GGFLAG_MOUSEOVER;
|
|
}
|
|
|
|
// pass message to a callback func that programmer specifies
|
|
if (this == mainframe && InputCallbackFunc) InputCallbackFunc(msg,arg1,arg2,arg3,arg4);
|
|
break;
|
|
}
|
|
int dragxrel = arg3-dragx;
|
|
int dragyrel = arg4-dragy;
|
|
if (dragstate==1) {
|
|
if (abs(dragxrel)+abs(dragyrel) >= DRAG_THRESHOLD)
|
|
dragstate=2;
|
|
} else if (dragstate==2) {
|
|
if (mousedowncontrol->flags & GGFLAG_MOVABLE) {
|
|
mousedowncontrol->x += dragxrel;
|
|
mousedowncontrol->y += dragyrel;
|
|
dragx = arg3;
|
|
dragy = arg4;
|
|
// glutPostRedisplay();
|
|
}
|
|
}
|
|
if (!(mousedowncontrol->flags & GGFLAG_MOUSEPRIORITY)) {
|
|
if (mousedowncontrol->InControl(arg3,arg4)) {
|
|
if (!(mousedowncontrol->flags & GGFLAG_DOWN))
|
|
mousedowncontrol->Message(GGMSG_DOWN,0,0,arg3,arg4);
|
|
} else {
|
|
if (mousedowncontrol->flags & GGFLAG_DOWN)
|
|
mousedowncontrol->Message(GGMSG_UP,0,0,arg3,arg4);
|
|
}
|
|
}
|
|
|
|
// must also pass message.
|
|
mousedowncontrol->Message(GGMSG_MOUSEMOTION,0,0,arg3,arg4);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ggFrame::AddControl(ggControl *newcontrol,int newx,int newy,int newxsize,int newysize)
|
|
{
|
|
if (!newcontrol) return;
|
|
|
|
newcontrol->SetPos(newx,newy,newxsize,newysize);
|
|
newcontrol->parent = this;
|
|
|
|
controls.push_back(newcontrol);
|
|
|
|
// keep track of hotkey info
|
|
if (newcontrol->flags & GGFLAG_HASHOTKEY && this==mainframe) {
|
|
ggButton *b = (ggButton*)newcontrol;
|
|
if (((ggButton*)newcontrol)->hotkey_extended) {
|
|
hotkeys_extended[b->hotkey] = b;
|
|
} else {
|
|
hotkeys[shiftize(b->hotkey)] = b;
|
|
}
|
|
}
|
|
|
|
// glutPostRedisplay();
|
|
}
|
|
|
|
void ggFrame::RemoveControl(ggControl *c)
|
|
// doesn't de-allocate the ggControl
|
|
{
|
|
if (!c) return;
|
|
|
|
if (c==mousedowncontrol) mousedowncontrol=NULL;
|
|
if (c==focus) focus=NULL;
|
|
|
|
vector<ggControl*>::iterator it = find(controls.begin(),controls.end(),c);
|
|
if (it!=controls.end()) controls.erase(it);
|
|
|
|
// keep track of hotkey info
|
|
if (c->flags & GGFLAG_HASHOTKEY && this==mainframe) {
|
|
ggButton *b = (ggButton*)c;
|
|
if (((ggButton*)c)->hotkey_extended) {
|
|
hotkeys_extended[b->hotkey] = NULL;
|
|
} else {
|
|
hotkeys[b->hotkey] = NULL;
|
|
}
|
|
}
|
|
|
|
// glutPostRedisplay();
|
|
}
|
|
|
|
void ggFrame::DeleteControl(ggControl *c)
|
|
// de-allocates itself and all stuff nested within
|
|
{
|
|
if (!c) return;
|
|
|
|
RemoveControl(c);
|
|
delete c;
|
|
// glutPostRedisplay();
|
|
}
|
|
|
|
ggControl *ggFrame::FindControl(int xpos,int ypos)
|
|
{
|
|
ggControl *ret;
|
|
|
|
ret = NULL;
|
|
|
|
for (int i=0; i<controls.size(); i++)
|
|
if (controls[i]->InControl(xpos,ypos))
|
|
ret = controls[i];
|
|
|
|
return ret;
|
|
}
|
|
/*
|
|
ggControl *ggFrame::FindControl(int xpos,int ypos)
|
|
{
|
|
for (int i=0; i<controls.size(); i++)
|
|
if (controls[i]->InControl(xpos,ypos)) return controls[i];
|
|
return NULL;
|
|
}
|
|
*/
|
|
void ggFrame::MoveToTop(ggControl *c)
|
|
{
|
|
// RemoveControl messes up mousedowncontrol and focus
|
|
bool re_set_mousedowncontrol = (c==mousedowncontrol);
|
|
bool re_set_focus = (c==focus);
|
|
RemoveControl(c);
|
|
AddControl(c);
|
|
if (re_set_mousedowncontrol) mousedowncontrol = c;
|
|
if (re_set_focus) focus = c;
|
|
}
|
|
|
|
void ggFrame::SetScale(float newscale)
|
|
{
|
|
scale = newscale;
|
|
// glutPostRedisplay();
|
|
}
|
|
|
|
void ggFrame::SetOffset(int ox,int oy)
|
|
{
|
|
offsetx = ox;
|
|
offsety = oy;
|
|
// glutPostRedisplay();
|
|
}
|
|
|
|
void ggFrame::PassBackNextMouseClick(void (*f)(int x,int y,int b,int state))
|
|
{
|
|
if (!f) {
|
|
flags &= ~GGFLAG_PASSBACK;
|
|
} else {
|
|
flags |= GGFLAG_PASSBACK;
|
|
}
|
|
passbackfunc = f;
|
|
}
|
|
|
|
void OnClose(int arg1,int arg2,int arg3,int arg4,int arg5)
|
|
{
|
|
// ((ggFrame*)arg1)->flags |= GGFLAG_DELETEME;
|
|
control_to_delete = (ggControl*)arg1;
|
|
}
|
|
|
|
void ggFrame::AddCloseButton()
|
|
{
|
|
ggButton *button = new ggButton("",OnClose,(int)this,0,0,0,0);
|
|
button->flags |= GGFLAG_ICON;
|
|
button->icon = GGICON_CLOSE;
|
|
button->SetPos(xsize-COL_HEIGHT+3,-COL_HEIGHT+3,COL_HEIGHT-6,COL_HEIGHT-6);
|
|
AddControl(button);
|
|
}
|
|
|
|
void ggFrame::SetDrawFunc(void (*f)())
|
|
{
|
|
drawFunc = f;
|
|
}
|
|
|
|
void ggFrame::SetFrameColor(float ra,float ga,float ba)
|
|
{
|
|
framer = ra;
|
|
frameg = ga;
|
|
frameb = ba;
|
|
// glutPostRedisplay();
|
|
}
|
|
|
|
void ggFrame::SetFrameColor(float ra,float ga,float ba,float aa)
|
|
{
|
|
framer = ra;
|
|
frameg = ga;
|
|
frameb = ba;
|
|
framea = aa;
|
|
// glutPostRedisplay();
|
|
}
|