mirror of
https://gitlab.winehq.org/wine/fontforge.git
synced 2025-10-14 02:47:57 +08:00
1204 lines
35 KiB
C
1204 lines
35 KiB
C
/* Copyright (C) 2000-2012 by George Williams */
|
|
/*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
|
|
* The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include "gdraw.h"
|
|
#include "gkeysym.h"
|
|
#include "ggadgetP.h"
|
|
#include "gwidget.h"
|
|
#include "ustring.h"
|
|
#include "gwidget.h"
|
|
|
|
static int GListTypeTime = 500; /* half a second between keystrokes */
|
|
static int GListScrollTime = 500; /* half a second between scrolls when mouse out of listbox */
|
|
|
|
static void GListSelected(GList *l,int frommouse,int index) {
|
|
GEvent e;
|
|
|
|
e.type = et_controlevent;
|
|
e.w = l->g.base;
|
|
e.u.control.subtype = et_listselected;
|
|
e.u.control.g = &l->g;
|
|
e.u.control.u.list.from_mouse = frommouse;
|
|
e.u.control.u.list.changed_index = index;
|
|
if ( l->g.handle_controlevent != NULL )
|
|
(l->g.handle_controlevent)(&l->g,&e);
|
|
else
|
|
GDrawPostEvent(&e);
|
|
}
|
|
|
|
static void GListDoubleClick(GList *l,int frommouse,int index) {
|
|
GEvent e;
|
|
|
|
e.type = et_controlevent;
|
|
e.w = l->g.base;
|
|
e.u.control.subtype = et_listdoubleclick;
|
|
e.u.control.g = &l->g;
|
|
e.u.control.u.list.from_mouse = frommouse;
|
|
e.u.control.u.list.changed_index = index;
|
|
if ( l->g.handle_controlevent != NULL )
|
|
(l->g.handle_controlevent)(&l->g,&e);
|
|
else
|
|
GDrawPostEvent(&e);
|
|
}
|
|
|
|
static void GListClose(GList *l) {
|
|
GEvent e;
|
|
|
|
e.type = et_close;
|
|
e.w = l->g.base;
|
|
if ( l->g.handle_controlevent != NULL )
|
|
(l->g.handle_controlevent)(&l->g,&e);
|
|
else
|
|
GDrawPostEvent(&e);
|
|
}
|
|
|
|
static int GListTopInWindow(GList *gl,int last) {
|
|
/* If we want to display last at the bottom of our list, then what line */
|
|
/* do we display at the top? */
|
|
int32 height = gl->g.inner.height, temp;
|
|
int l;
|
|
|
|
for ( l=last; l>=0; --l ) {
|
|
temp = GTextInfoGetHeight(gl->g.base,gl->ti[l],gl->font);
|
|
if ( height<temp )
|
|
return( l==last?last:l+1 ); /* if we can't even fit one line on, pretend it fits */
|
|
height -= temp;
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
static int GListLinesInWindow(GList *gl,int first) {
|
|
/* Ok, the first line displayed is "first", how many others do we have */
|
|
/* room for? */
|
|
int32 height = gl->g.inner.height, temp;
|
|
int l, lcnt=0;
|
|
|
|
for ( l=first; l<gl->ltot; ++l ) {
|
|
temp = GTextInfoGetHeight(gl->g.base,gl->ti[l],gl->font);
|
|
if ( height<temp )
|
|
return( l==first?1:lcnt ); /* if we can't even fit one line on, pretend it fits */
|
|
height -= temp;
|
|
++lcnt;
|
|
}
|
|
if ( height>0 ) {
|
|
if ( gl->fh==0 ) {
|
|
int as, ds, ld;
|
|
GDrawWindowFontMetrics(gl->g.base,gl->font,&as, &ds, &ld);
|
|
gl->fh = as+ds;
|
|
gl->as = as;
|
|
}
|
|
lcnt += height/gl->fh;
|
|
}
|
|
if ( lcnt==0 )
|
|
lcnt=1;
|
|
return( lcnt );
|
|
}
|
|
|
|
static int GListAlphaCompare(const void *v1, const void *v2) {
|
|
GTextInfo * const *pt1 = v1, * const *pt2 = v2;
|
|
return( GTextInfoCompare(*pt1,*pt2));
|
|
}
|
|
|
|
static void GListOrderIt(GList *gl) {
|
|
qsort(gl->ti,gl->ltot,sizeof(GTextInfo *),gl->orderer);
|
|
if ( gl->backwards ) {
|
|
int i;
|
|
GTextInfo *ti;
|
|
for ( i=0; i<gl->ltot/2; ++i ) {
|
|
ti = gl->ti[i];
|
|
gl->ti[i] = gl->ti[gl->ltot-1-i];
|
|
gl->ti[gl->ltot-1-i] = ti;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void GListClearSel(GList *gl) {
|
|
int i;
|
|
|
|
for ( i=0; i<gl->ltot; ++i )
|
|
gl->ti[i]->selected = false;
|
|
}
|
|
|
|
static int GListAnyOtherSels(GList *gl, int pos) {
|
|
int i;
|
|
|
|
for ( i=0; i<gl->ltot; ++i )
|
|
if ( gl->ti[i]->selected && i!=pos )
|
|
return( true );
|
|
|
|
return( false );
|
|
}
|
|
|
|
static int32 GListGetFirstSelPos(GGadget *g) {
|
|
int i;
|
|
GList *gl = (GList *) g;
|
|
|
|
for ( i=0; i<gl->ltot; ++i )
|
|
if ( gl->ti[i]->selected )
|
|
return( i );
|
|
|
|
return( -1 );
|
|
}
|
|
|
|
static void GListSelect(GGadget *g, int32 pos, int32 sel) {
|
|
GList *gl = (GList *) g;
|
|
int i;
|
|
|
|
if ( pos==-1 && (gl->multiple_sel || (!sel && !gl->exactly_one)) ) {
|
|
/* Select/deselect all */
|
|
for ( i=0; i<gl->ltot; ++i )
|
|
gl->ti[i]->selected = sel;
|
|
_ggadget_redraw(g);
|
|
return;
|
|
}
|
|
|
|
if ( pos>=gl->ltot || pos<0 )
|
|
return;
|
|
if ( gl->exactly_one && !sel )
|
|
return;
|
|
if ( !gl->multiple_sel && sel )
|
|
GListClearSel(gl);
|
|
if ( gl->ltot>0 ) {
|
|
gl->ti[pos]->selected = sel;
|
|
_ggadget_redraw(g);
|
|
}
|
|
}
|
|
|
|
static void GListSelectOne(GGadget *g, int32 pos) {
|
|
GList *gl = (GList *) g;
|
|
|
|
GListClearSel(gl);
|
|
if ( pos>=gl->ltot ) pos = gl->ltot-1;
|
|
if ( pos<0 ) pos = 0;
|
|
if ( gl->ltot>0 ) {
|
|
gl->ti[pos]->selected = true;
|
|
_ggadget_redraw(g);
|
|
}
|
|
}
|
|
|
|
static int32 GListIsItemSelected(GGadget *g, int32 pos) {
|
|
GList *gl = (GList *) g;
|
|
|
|
if ( pos>=gl->ltot )
|
|
return( false );
|
|
if ( pos<0 )
|
|
return( false );
|
|
if ( gl->ltot>0 )
|
|
return( gl->ti[pos]->selected );
|
|
|
|
return( false );
|
|
}
|
|
|
|
static void GListExpandSelection(GList *gl,int pos) {
|
|
int i;
|
|
|
|
if ( gl->start!=65535 ) {
|
|
if ( gl->start<gl->end )
|
|
for ( i=gl->start; i<=gl->end; ++i )
|
|
gl->ti[i]->selected = false;
|
|
else
|
|
for ( i=gl->start; i>=gl->end; --i )
|
|
gl->ti[i]->selected = false;
|
|
} else
|
|
gl->start = pos;
|
|
gl->end = pos;
|
|
if ( gl->start<gl->end )
|
|
for ( i=gl->start; i<=gl->end; ++i )
|
|
gl->ti[i]->selected = true;
|
|
else
|
|
for ( i=gl->start; i>=gl->end; --i )
|
|
gl->ti[i]->selected = true;
|
|
}
|
|
|
|
static int GListIndexFromPos(GList *gl,int y) {
|
|
int i, height;
|
|
|
|
y -= gl->g.inner.y;
|
|
if ( y<0 ) y=0;
|
|
if ( y>=gl->g.inner.height ) y = gl->g.inner.height-1;
|
|
for ( i=gl->loff, height=0; i<gl->ltot; ++i ) {
|
|
int temp = GTextInfoGetHeight(gl->g.base,gl->ti[i],gl->font);
|
|
if ( height+temp>y )
|
|
break;
|
|
height += temp;
|
|
}
|
|
if ( i==gl->ltot )
|
|
return( -1 );
|
|
if ( gl->ti[i]->disabled )
|
|
return( -1 );
|
|
return( i );
|
|
}
|
|
|
|
static void GListScrollBy(GList *gl,int loff,int xoff) {
|
|
int top = GListTopInWindow(gl,gl->ltot-1);
|
|
int ydiff, i;
|
|
|
|
if ( gl->loff + loff < 0 )
|
|
loff = -gl->loff;
|
|
else if ( gl->loff + loff > top )
|
|
loff = top-gl->loff;
|
|
if ( xoff+gl->xoff<0 )
|
|
xoff = -gl->xoff;
|
|
else if ( xoff+gl->xoff+gl->g.inner.width > gl->xmax ) {
|
|
xoff = gl->xmax-gl->g.inner.width-gl->xoff;
|
|
if ( xoff<0 ) xoff = 0;
|
|
}
|
|
if ( loff == 0 && xoff==0 )
|
|
return;
|
|
|
|
ydiff = 0;
|
|
if ( loff>0 ) {
|
|
for ( i=0; i<loff && ydiff<gl->g.inner.height; ++i )
|
|
ydiff += GTextInfoGetHeight(gl->g.base,gl->ti[i+gl->loff],gl->font);
|
|
} else if ( loff<0 ) {
|
|
for ( i=loff; i<0 && -ydiff<gl->g.inner.height; ++i )
|
|
ydiff -= GTextInfoGetHeight(gl->g.base,gl->ti[i+gl->loff],gl->font);
|
|
}
|
|
if ( !GDrawIsVisible(gl->g.base))
|
|
return;
|
|
GDrawForceUpdate(gl->g.base);
|
|
gl->loff += loff; gl->xoff += xoff;
|
|
if ( ydiff>=gl->g.inner.height || -ydiff >= gl->g.inner.height )
|
|
_ggadget_redraw(&gl->g);
|
|
else if ( ydiff!=0 || xoff!=0 )
|
|
GDrawScroll(gl->g.base,&gl->g.inner,xoff,ydiff);
|
|
if ( loff!=0 && gl->vsb!=NULL )
|
|
GScrollBarSetPos(&gl->vsb->g,gl->loff);
|
|
}
|
|
|
|
static int GListFindPosition(GList *gl,unichar_t *text) {
|
|
GTextInfo temp, *ptemp=&temp;
|
|
int i, order;
|
|
|
|
if ( gl->orderer!=NULL ) {
|
|
memset(&temp,'\0',sizeof(temp));
|
|
temp.text = text;
|
|
|
|
/* I don't think I need to write a binary search here... */
|
|
for ( i=0; i<gl->ltot; ++i ) {
|
|
order = (gl->orderer)(&ptemp,&gl->ti[i]);
|
|
if (( order<= 0 && !gl->backwards ) || ( order>=0 && gl->backwards ))
|
|
return( i );
|
|
}
|
|
return( 0 );
|
|
} else {
|
|
for ( i=0; i<gl->ltot; ++i ) {
|
|
if (u_strmatch(text,gl->ti[i]->text)==0 )
|
|
return( i );
|
|
}
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
static int GListAdjustPos(GGadget *g,int pos) {
|
|
GList *gl = (GList *) g;
|
|
int newoff = gl->loff;
|
|
|
|
if ( pos<gl->loff ) {
|
|
if (( newoff = pos-1)<0 ) newoff = 0;
|
|
if ( GListLinesInWindow(gl,newoff)<2 )
|
|
newoff = pos;
|
|
} else if ( pos >= gl->loff + GListLinesInWindow(gl,gl->loff) ) {
|
|
newoff = GListTopInWindow(gl,pos);
|
|
if ( pos!=gl->ltot-1 && GListLinesInWindow(gl,newoff+1)>=2 )
|
|
++newoff;
|
|
}
|
|
return( newoff );
|
|
}
|
|
|
|
static void GListShowPos(GGadget *g,int32 pos) {
|
|
GList *gl = (GList *) g;
|
|
int newoff = GListAdjustPos(g,pos);
|
|
if ( newoff!=gl->loff )
|
|
GListScrollBy(gl,newoff-gl->loff,0);
|
|
}
|
|
|
|
static void GListScrollToText(GGadget *g,const unichar_t *text,int32 sel) {
|
|
GList *gl = (GList *) g;
|
|
int pos;
|
|
|
|
pos = GListFindPosition(gl,(unichar_t *) text);
|
|
if ( sel && pos<gl->ltot ) {
|
|
GListClearSel(gl);
|
|
if ( gl->exactly_one || u_strmatch(text,gl->ti[pos]->text)==0 )
|
|
gl->ti[pos]->selected = true;
|
|
}
|
|
gl->loff = GListAdjustPos(g,pos);
|
|
if ( gl->vsb!=NULL )
|
|
GScrollBarSetPos(&gl->vsb->g,gl->loff);
|
|
_ggadget_redraw(g);
|
|
}
|
|
|
|
static void GListSetOrderer(GGadget *g,int (*orderer)(const void *, const void *)) {
|
|
GList *gl = (GList *) g;
|
|
|
|
gl->orderer = orderer;
|
|
if ( orderer!=NULL ) {
|
|
GListOrderIt(gl);
|
|
GListScrollBy(gl,-gl->loff,-gl->xoff);
|
|
_ggadget_redraw(&gl->g);
|
|
}
|
|
}
|
|
|
|
static int glist_scroll(GGadget *g, GEvent *event);
|
|
static void GListCheckSB(GList *gl) {
|
|
if ( gl->vsb==NULL ) {
|
|
GGadgetData gd;
|
|
memset(&gd,'\0',sizeof(gd));
|
|
gd.pos.y = gl->g.r.y; gd.pos.height = gl->g.r.height;
|
|
gd.pos.width = GDrawPointsToPixels(gl->g.base,_GScrollBar_Width);
|
|
gd.pos.x = gl->g.r.x+gl->g.r.width - gd.pos.width;
|
|
gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert|gg_pos_use0;
|
|
gd.handle_controlevent = glist_scroll;
|
|
gl->vsb = (GScrollBar *) GScrollBarCreate(gl->g.base,&gd,gl);
|
|
gl->vsb->g.contained = true;
|
|
|
|
gd.pos.width += GDrawPointsToPixels(gl->g.base,1);
|
|
gl->g.r.width -= gd.pos.width;
|
|
gl->g.inner.width -= gd.pos.width;
|
|
}
|
|
if ( gl->always_show_sb || GListLinesInWindow(gl,0)<gl->ltot ) {
|
|
if ( gl->vsb->g.state == gs_invisible ) {
|
|
int wid = gl->vsb->g.r.width + GDrawPointsToPixels(gl->g.base,1);
|
|
gl->vsb->g.state = gs_enabled;
|
|
gl->g.r.width -= wid;
|
|
gl->g.inner.width -= wid;
|
|
}
|
|
GScrollBarSetBounds(&gl->vsb->g,0,gl->ltot,GListLinesInWindow(gl,0));
|
|
GScrollBarSetPos(&gl->vsb->g,gl->loff);
|
|
} else {
|
|
if ( gl->vsb->g.state != gs_invisible ) {
|
|
int wid = gl->vsb->g.r.width + GDrawPointsToPixels(gl->g.base,1);
|
|
gl->vsb->g.state = gs_invisible;
|
|
gl->g.r.width += wid;
|
|
gl->g.inner.width += wid;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int GListFindXMax(GList *gl) {
|
|
int i, width=0, temp;
|
|
|
|
for ( i=0; i<gl->ltot; ++i ) {
|
|
temp = GTextInfoGetWidth(gl->g.base,gl->ti[i],gl->font);
|
|
if ( temp>width ) width=temp;
|
|
}
|
|
gl->xmax = width;
|
|
return( width );
|
|
}
|
|
|
|
static void GListSetList(GGadget *g,GTextInfo **ti,int32 docopy) {
|
|
GList *gl = (GList *) g;
|
|
int same;
|
|
|
|
GTextInfoArrayFree(gl->ti);
|
|
if ( docopy || ti==NULL )
|
|
ti = GTextInfoArrayCopy(ti);
|
|
gl->ti = ti;
|
|
gl->ltot = GTextInfoArrayCount(ti);
|
|
if ( gl->orderer!=NULL )
|
|
GListOrderIt(gl);
|
|
gl->loff = gl->xoff = 0;
|
|
gl->hmax = GTextInfoGetMaxHeight(g->base,ti,gl->font,&same);
|
|
gl->sameheight = same;
|
|
GListCheckSB(gl);
|
|
_ggadget_redraw(&gl->g);
|
|
}
|
|
|
|
static void GListClear(GGadget *g) {
|
|
GListSetList(g,NULL,true);
|
|
}
|
|
|
|
static GTextInfo **GListGetList(GGadget *g,int32 *len) {
|
|
GList *gl = (GList *) g;
|
|
if ( len!=NULL ) *len = gl->ltot;
|
|
return( gl->ti );
|
|
}
|
|
|
|
static GTextInfo *GListGetListItem(GGadget *g,int32 pos) {
|
|
GList *gl = (GList *) g;
|
|
if ( pos<0 || pos>=gl->ltot )
|
|
return( NULL );
|
|
|
|
return(gl->ti[pos]);
|
|
}
|
|
|
|
static int glist_expose(GWindow pixmap, GGadget *g, GEvent *event) {
|
|
GList *gl = (GList *) g;
|
|
GRect old0, old1, old2;
|
|
Color fg, dfg;
|
|
int y, l, ymax;
|
|
|
|
if ( g->state == gs_invisible )
|
|
return( false );
|
|
|
|
GDrawPushClip(pixmap,&event->u.expose.rect,&old0);
|
|
GDrawPushClip(pixmap,&g->r,&old1);
|
|
|
|
GBoxDrawBackground(pixmap,&g->r,g->box, g->state,false);
|
|
if ( g->box->border_type!=bt_none ||
|
|
(g->box->flags&(box_foreground_border_inner|box_foreground_border_outer|box_active_border_inner))!=0 ) {
|
|
GBoxDrawBorder(pixmap,&g->r,g->box,g->state,false);
|
|
|
|
GDrawPushClip(pixmap,&g->inner,&old2);
|
|
}
|
|
|
|
fg = g->state==gs_disabled?g->box->disabled_foreground:g->box->main_foreground;
|
|
dfg = g->box->disabled_foreground;
|
|
y = g->inner.y;
|
|
ymax = g->inner.y+g->inner.height;
|
|
if ( ymax>event->u.expose.rect.y+event->u.expose.rect.height )
|
|
ymax = event->u.expose.rect.y+event->u.expose.rect.height;
|
|
for ( l = gl->loff; y<ymax && l<gl->ltot; ++l ) {
|
|
if ( y+gl->hmax > event->u.expose.rect.y )
|
|
y += GTextInfoDraw(pixmap,g->inner.x-gl->xoff,y,gl->ti[l],
|
|
gl->font,gl->ti[l]->disabled?dfg:fg,g->box->active_border,
|
|
ymax);
|
|
else if ( gl->sameheight )
|
|
y += gl->hmax;
|
|
else
|
|
y += GTextInfoGetHeight(pixmap,gl->ti[l],gl->font);
|
|
}
|
|
if ( g->box->border_type!=bt_none ||
|
|
(g->box->flags&(box_foreground_border_inner|box_foreground_border_outer|box_active_border_inner))!=0 )
|
|
GDrawPopClip(pixmap,&old2);
|
|
GDrawPopClip(pixmap,&old1);
|
|
GDrawPopClip(pixmap,&old0);
|
|
return( true );
|
|
}
|
|
|
|
static void glist_scroll_selbymouse(GList *gl, GEvent *event) {
|
|
int loff=0, xoff=0, pos;
|
|
|
|
if ( event->u.mouse.y<gl->g.inner.y ) {
|
|
if ( gl->loff>0 ) loff = -1;
|
|
} else if ( event->u.mouse.y >= gl->g.inner.y+gl->g.inner.height ) {
|
|
int top = GListTopInWindow(gl,gl->ltot-1);
|
|
if ( gl->loff<top ) loff = 1;
|
|
}
|
|
if ( event->u.mouse.x<gl->g.inner.x ) {
|
|
xoff = -GDrawPointsToPixels(gl->g.base,6);
|
|
} else if ( event->u.mouse.x >= gl->g.inner.x+gl->g.inner.width ) {
|
|
xoff = GDrawPointsToPixels(gl->g.base,6);
|
|
}
|
|
GListScrollBy(gl,loff,xoff);
|
|
pos = GListIndexFromPos(gl,event->u.mouse.y);
|
|
if ( pos==-1 || pos == gl->end )
|
|
/* Do Nothing, nothing selectable */;
|
|
else if ( !gl->multiple_sel ) {
|
|
GListClearSel(gl);
|
|
gl->ti[pos]->selected = true;
|
|
gl->start = gl->end = pos;
|
|
_ggadget_redraw(&gl->g);
|
|
} else {
|
|
GListExpandSelection(gl,pos);
|
|
gl->end = pos;
|
|
_ggadget_redraw(&gl->g);
|
|
}
|
|
}
|
|
|
|
static int glist_mouse(GGadget *g, GEvent *event) {
|
|
GList *gl = (GList *) g;
|
|
int pos;
|
|
|
|
if ( !g->takes_input || (g->state!=gs_active && g->state!=gs_enabled && g->state!=gs_focused))
|
|
return( false );
|
|
|
|
if ( event->type == et_crossing )
|
|
return( false );
|
|
if (( event->type==et_mouseup || event->type==et_mousedown ) &&
|
|
(event->u.mouse.button>=4 && event->u.mouse.button<=7)) {
|
|
if ( gl->vsb!=NULL )
|
|
return( GGadgetDispatchEvent(&gl->vsb->g,event));
|
|
else
|
|
return( true );
|
|
}
|
|
if ( event->type==et_mousemove && !gl->pressed && !gl->parentpressed ) {
|
|
if ( GGadgetWithin(g,event->u.mouse.x,event->u.mouse.y) ) {
|
|
if ( gl->popup_callback!=NULL )
|
|
(gl->popup_callback)(g,GListIndexFromPos(gl,event->u.mouse.y));
|
|
else if ( g->popup_msg )
|
|
GGadgetPreparePopup(g->base,g->popup_msg);
|
|
}
|
|
return( true );
|
|
} else if ( event->type==et_mouseup && gl->parentpressed /* &&
|
|
!GGadgetInnerWithin(&gl->g,event->u.mouse.x,event->u.mouse.y)*/ ) {
|
|
gl->parentpressed = false;
|
|
GDrawPointerUngrab(GDrawGetDisplayOfWindow(gl->g.base));
|
|
} else if ( event->type==et_mousemove && gl->parentpressed &&
|
|
GGadgetInnerWithin(&gl->g,event->u.mouse.x,event->u.mouse.y)) {
|
|
if ( gl->pressed == NULL )
|
|
gl->pressed = GDrawRequestTimer(g->base,GListScrollTime,GListScrollTime,NULL);
|
|
GDrawPointerUngrab(GDrawGetDisplayOfWindow(gl->g.base));
|
|
gl->parentpressed = false;
|
|
glist_scroll_selbymouse(gl,event);
|
|
return( true );
|
|
} else if ( event->type==et_mousemove && gl->pressed ) {
|
|
glist_scroll_selbymouse(gl,event);
|
|
return( true );
|
|
} else if ( event->type==et_mousedown ) {
|
|
if ( gl->pressed == NULL )
|
|
gl->pressed = GDrawRequestTimer(g->base,GListScrollTime,GListScrollTime,NULL);
|
|
pos = GListIndexFromPos(gl,event->u.mouse.y);
|
|
if ( pos==-1 )
|
|
return( true ); /* Do Nothing, nothing selectable */
|
|
else if ( !gl->exactly_one && gl->ti[pos]->selected &&
|
|
(event->u.mouse.state&(ksm_control|ksm_shift))) {
|
|
gl->ti[pos]->selected = false;
|
|
gl->start = gl->end = 0xffff;
|
|
} else if ( !gl->multiple_sel ||
|
|
(!gl->ti[pos]->selected && !(event->u.mouse.state&(ksm_control|ksm_shift)))) {
|
|
GListClearSel(gl);
|
|
gl->ti[pos]->selected = true;
|
|
gl->start = gl->end = pos;
|
|
} else if ( event->u.mouse.state&ksm_control ||
|
|
((event->u.mouse.state&ksm_shift) && gl->ti[pos]->selected)) {
|
|
gl->ti[pos]->selected = !gl->ti[pos]->selected;
|
|
gl->start = gl->end = pos;
|
|
} else if ( event->u.mouse.state&ksm_shift ) {
|
|
GListExpandSelection(gl,pos);
|
|
} else {
|
|
gl->ti[pos]->selected = true;
|
|
gl->start = gl->end = pos;
|
|
}
|
|
_ggadget_redraw(&gl->g);
|
|
} else if ( event->type==et_mouseup && gl->pressed ) {
|
|
GDrawCancelTimer(gl->pressed); gl->pressed = NULL;
|
|
if ( GGadgetInnerWithin(&gl->g,event->u.mouse.x,event->u.mouse.y) ) {
|
|
pos = GListIndexFromPos(gl,event->u.mouse.y);
|
|
if ( !(event->u.mouse.state&(ksm_control|ksm_shift)) || gl->start!=0xffff )
|
|
glist_scroll_selbymouse(gl,event);
|
|
if ( event->u.mouse.clicks==2 )
|
|
GListDoubleClick(gl,true,pos);
|
|
else
|
|
GListSelected(gl,true,pos);
|
|
}
|
|
} else
|
|
return( false );
|
|
|
|
return( true );
|
|
}
|
|
|
|
static int glist_key(GGadget *g, GEvent *event) {
|
|
GList *gl = (GList *) g;
|
|
uint16 keysym = event->u.chr.keysym;
|
|
int sofar_pos = gl->sofar_pos;
|
|
int loff, xoff, sel=-1;
|
|
int refresh = false;
|
|
|
|
if ( event->type == et_charup )
|
|
return( false );
|
|
if ( !g->takes_input || (g->state!=gs_enabled && g->state!=gs_active && g->state!=gs_focused ))
|
|
return(false );
|
|
|
|
if ( gl->ispopup && event->u.chr.keysym == GK_Return ) {
|
|
GListDoubleClick(gl,false,-1);
|
|
return( true );
|
|
} else if ( gl->ispopup && event->u.chr.keysym == GK_Escape ) {
|
|
GListClose(gl);
|
|
return( true );
|
|
}
|
|
|
|
if ( event->u.chr.keysym == GK_Return || event->u.chr.keysym == GK_Tab ||
|
|
event->u.chr.keysym == GK_BackTab || event->u.chr.keysym == GK_Escape )
|
|
return( false );
|
|
|
|
GDrawCancelTimer(gl->enduser); gl->enduser = NULL; gl->sofar_pos = 0;
|
|
|
|
loff = 0x80000000; xoff = 0x80000000; sel = -1;
|
|
if ( keysym == GK_Home || keysym == GK_KP_Home || keysym == GK_Begin || keysym == GK_KP_Begin ) {
|
|
loff = -gl->loff;
|
|
xoff = -gl->xoff;
|
|
sel = 0;
|
|
} else if ( keysym == GK_End || keysym == GK_KP_End ) {
|
|
loff = GListTopInWindow(gl,gl->ltot-1)-gl->loff;
|
|
xoff = -gl->xoff;
|
|
sel = gl->ltot-1;
|
|
} else if ( keysym == GK_Up || keysym == GK_KP_Up ) {
|
|
if (( sel = GListGetFirstSelPos(&gl->g)-1 )<0 ) {
|
|
/*if ( gl->loff!=0 ) loff = -1; else loff = 0;*/
|
|
sel = 0;
|
|
}
|
|
} else if ( keysym == GK_Down || keysym == GK_KP_Down ) {
|
|
if (( sel = GListGetFirstSelPos(&gl->g))!= -1 )
|
|
++sel;
|
|
else
|
|
/*if ( gl->loff + GListLinesInWindow(gl,gl->loff)<gl->ltot ) loff = 1; else loff = 0;*/
|
|
sel = 0;
|
|
} else if ( keysym == GK_Left || keysym == GK_KP_Left ) {
|
|
xoff = -GDrawPointsToPixels(gl->g.base,6);
|
|
} else if ( keysym == GK_Right || keysym == GK_KP_Right ) {
|
|
xoff = GDrawPointsToPixels(gl->g.base,6);
|
|
} else if ( keysym == GK_Page_Up || keysym == GK_KP_Page_Up ) {
|
|
loff = GListTopInWindow(gl,gl->loff);
|
|
if ( loff == gl->loff ) /* Normally we leave one line in window from before, except if only one line fits */
|
|
loff = GListTopInWindow(gl,gl->loff-1);
|
|
loff -= gl->loff;
|
|
if (( sel = GListGetFirstSelPos(&gl->g))!= -1 ) {
|
|
if (( sel += loff )<0 ) sel = 0;
|
|
}
|
|
} else if ( keysym == GK_Page_Down || keysym == GK_KP_Page_Down ) {
|
|
loff = GListLinesInWindow(gl,gl->loff)-1;
|
|
if ( loff<=0 ) loff = 1;
|
|
if ( loff + gl->loff >= gl->ltot )
|
|
loff = GListTopInWindow(gl,gl->ltot-1)-gl->loff;
|
|
if (( sel = GListGetFirstSelPos(&gl->g))!= -1 ) {
|
|
if (( sel += loff )>=gl->ltot ) sel = gl->ltot-1;
|
|
}
|
|
} else if ( keysym == GK_BackSpace && gl->orderer ) {
|
|
/* ordered lists may be reversed by typing backspace */
|
|
gl->backwards = !gl->backwards;
|
|
GListOrderIt(gl);
|
|
sel = GListGetFirstSelPos(&gl->g);
|
|
if ( sel!=-1 ) {
|
|
int top = GListTopInWindow(gl,gl->ltot-1);
|
|
gl->loff = sel-1;
|
|
if ( gl->loff > top )
|
|
gl->loff = top;
|
|
if ( sel-1<0 )
|
|
gl->loff = 0;
|
|
}
|
|
GScrollBarSetPos(&gl->vsb->g,gl->loff);
|
|
_ggadget_redraw(&gl->g);
|
|
return( true );
|
|
} else if ( event->u.chr.chars[0]!='\0' && gl->orderer ) {
|
|
int len = u_strlen(event->u.chr.chars);
|
|
if ( sofar_pos+len >= gl->sofar_max ) {
|
|
if ( gl->sofar_max == 0 )
|
|
gl->sofar = galloc((gl->sofar_max = len+10) * sizeof(unichar_t));
|
|
else
|
|
gl->sofar = grealloc(gl->sofar,(gl->sofar_max = sofar_pos+len+10)*sizeof(unichar_t));
|
|
}
|
|
u_strcpy(gl->sofar+sofar_pos,event->u.chr.chars);
|
|
gl->sofar_pos = sofar_pos + len;
|
|
sel = GListFindPosition(gl,gl->sofar);
|
|
gl->enduser = GDrawRequestTimer(gl->g.base,GListTypeTime,0,NULL);
|
|
}
|
|
|
|
if ( loff==0x80000000 && sel>=0 ) {
|
|
if ( sel>=gl->ltot ) sel = gl->ltot-1;
|
|
if ( sel<gl->loff ) loff = sel-gl->loff;
|
|
else if ( sel>=gl->loff+GListLinesInWindow(gl,gl->loff) )
|
|
loff = sel-(gl->loff+GListLinesInWindow(gl,gl->loff)-1);
|
|
} else
|
|
sel = -1;
|
|
if ( sel!=-1 ) {
|
|
int wassel = gl->ti[sel]->selected;
|
|
refresh = GListAnyOtherSels(gl,sel) || !wassel;
|
|
GListSelectOne(&gl->g,sel);
|
|
if ( refresh )
|
|
GListSelected(gl,false,sel);
|
|
}
|
|
if ( loff!=0x80000000 || xoff!=0x80000000 ) {
|
|
if ( loff==0x80000000 ) loff = 0;
|
|
if ( xoff==0x80000000 ) xoff = 0;
|
|
GListScrollBy(gl,loff,xoff);
|
|
}
|
|
if ( refresh )
|
|
_ggadget_redraw(g);
|
|
if ( loff!=0x80000000 || xoff!=0x80000000 || sel!=-1 )
|
|
return( true );
|
|
|
|
return( false );
|
|
}
|
|
|
|
static int glist_timer(GGadget *g, GEvent *event) {
|
|
GList *gl = (GList *) g;
|
|
|
|
if ( event->u.timer.timer == gl->enduser ) {
|
|
gl->enduser = NULL;
|
|
gl->sofar_pos = 0;
|
|
return( true );
|
|
} else if ( event->u.timer.timer == gl->pressed ) {
|
|
GEvent e;
|
|
e.type = et_mousemove;
|
|
GDrawGetPointerPosition(g->base,&e);
|
|
if ( e.u.mouse.x<g->inner.x || e.u.mouse.y <g->inner.y ||
|
|
e.u.mouse.x >= g->inner.x + g->inner.width ||
|
|
e.u.mouse.y >= g->inner.y + g->inner.height )
|
|
glist_scroll_selbymouse(gl,&e);
|
|
return( true );
|
|
}
|
|
return( false );
|
|
}
|
|
|
|
static int glist_scroll(GGadget *g, GEvent *event) {
|
|
int loff = 0;
|
|
enum sb sbt = event->u.control.u.sb.type;
|
|
GList *gl = (GList *) (g->data);
|
|
|
|
g = (GGadget *) gl;
|
|
|
|
if ( sbt==et_sb_top )
|
|
loff = -gl->loff;
|
|
else if ( sbt==et_sb_bottom )
|
|
loff = GListTopInWindow(gl,gl->ltot-1)-gl->loff;
|
|
else if ( sbt==et_sb_up ) {
|
|
if ( gl->loff!=0 ) loff = -1; else loff = 0;
|
|
} else if ( sbt==et_sb_down ) {
|
|
if ( gl->loff + GListLinesInWindow(gl,gl->loff)<gl->ltot ) loff = 1; else loff = 0;
|
|
} else if ( sbt==et_sb_uppage ) {
|
|
loff = GListTopInWindow(gl,gl->loff);
|
|
if ( loff == gl->loff ) /* Normally we leave one line in window from before, except if only one line fits */
|
|
loff = GListTopInWindow(gl,gl->loff-1);
|
|
loff -= gl->loff;
|
|
} else if ( sbt==et_sb_downpage ) {
|
|
loff = GListLinesInWindow(gl,gl->loff)-1;
|
|
if ( loff<=0 ) loff = 1;
|
|
if ( loff + gl->loff >= gl->ltot )
|
|
loff = GListTopInWindow(gl,gl->ltot-1)-gl->loff;
|
|
} else /* if ( sbt==et_sb_thumb || sbt==et_sb_thumbrelease ) */ {
|
|
loff = event->u.control.u.sb.pos - gl->loff;
|
|
}
|
|
GListScrollBy(gl,loff,0);
|
|
return( true );
|
|
}
|
|
|
|
static void GList_destroy(GGadget *g) {
|
|
GList *gl = (GList *) g;
|
|
|
|
if ( gl==NULL )
|
|
return;
|
|
GDrawCancelTimer(gl->enduser);
|
|
GDrawCancelTimer(gl->pressed);
|
|
if ( gl->freeti )
|
|
GTextInfoArrayFree(gl->ti);
|
|
free(gl->sofar);
|
|
if ( gl->vsb!=NULL )
|
|
(gl->vsb->g.funcs->destroy)(&gl->vsb->g);
|
|
_ggadget_destroy(g);
|
|
}
|
|
|
|
static void GListSetFont(GGadget *g,FontInstance *new) {
|
|
GList *gl = (GList *) g;
|
|
int same;
|
|
|
|
gl->font = new;
|
|
gl->hmax = GTextInfoGetMaxHeight(gl->g.base,gl->ti,gl->font,&same);
|
|
gl->sameheight = same;
|
|
}
|
|
|
|
static FontInstance *GListGetFont(GGadget *g) {
|
|
GList *b = (GList *) g;
|
|
return( b->font );
|
|
}
|
|
|
|
static void glist_redraw(GGadget *g) {
|
|
GList *gl = (GList *) g;
|
|
if ( gl->vsb!=NULL )
|
|
_ggadget_redraw((GGadget *) (gl->vsb));
|
|
_ggadget_redraw(g);
|
|
}
|
|
|
|
static void glist_move(GGadget *g, int32 x, int32 y ) {
|
|
GList *gl = (GList *) g;
|
|
if ( gl->vsb!=NULL )
|
|
_ggadget_move((GGadget *) (gl->vsb),x+(gl->vsb->g.r.x-g->r.x),y);
|
|
_ggadget_move(g,x,y);
|
|
}
|
|
|
|
static void glist_resize(GGadget *g, int32 width, int32 height ) {
|
|
GList *gl = (GList *) g;
|
|
if ( gl->vsb!=NULL ) {
|
|
int oldwidth = gl->vsb->g.r.x+gl->vsb->g.r.width-g->r.x;
|
|
_ggadget_move((GGadget *) (gl->vsb),gl->vsb->g.r.x+width-oldwidth,gl->vsb->g.r.y);
|
|
_ggadget_resize(g,width-(oldwidth-g->r.width), height);
|
|
_ggadget_resize((GGadget *) (gl->vsb),gl->vsb->g.r.width,height);
|
|
GListCheckSB(gl);
|
|
} else
|
|
_ggadget_resize(g,width,height);
|
|
}
|
|
|
|
static GRect *glist_getsize(GGadget *g, GRect *r ) {
|
|
GList *gl = (GList *) g;
|
|
_ggadget_getsize(g,r);
|
|
if ( gl->vsb!=NULL )
|
|
r->width = gl->vsb->g.r.x+gl->vsb->g.r.width-g->r.x;
|
|
return( r );
|
|
}
|
|
|
|
static void glist_setvisible(GGadget *g, int visible ) {
|
|
GList *gl = (GList *) g;
|
|
if ( gl->vsb!=NULL ) _ggadget_setvisible(&gl->vsb->g,visible);
|
|
_ggadget_setvisible(g,visible);
|
|
}
|
|
|
|
static void glist_setenabled(GGadget *g, int enabled ) {
|
|
GList *gl = (GList *) g;
|
|
if ( gl->vsb!=NULL ) _ggadget_setenabled(&gl->vsb->g,enabled);
|
|
_ggadget_setenabled(g,enabled);
|
|
}
|
|
|
|
static void GListGetDesiredSize(GGadget *g,GRect *outer, GRect *inner) {
|
|
GList *gl = (GList *) g;
|
|
int width=0, height=0, temp;
|
|
int bp = GBoxBorderWidth(gl->g.base,gl->g.box);
|
|
int i;
|
|
|
|
/* can't deal with eliptical scrolling lists nor diamond ones. Just rects and roundrects */
|
|
if ( g->desired_width<=0 ) {
|
|
GListFindXMax(gl);
|
|
|
|
width = gl->xmax;
|
|
temp = GDrawPointsToPixels(gl->g.base,50);
|
|
if ( width<temp ) width = temp;
|
|
width += GDrawPointsToPixels(gl->g.base,_GScrollBar_Width) +
|
|
GDrawPointsToPixels(gl->g.base,1);
|
|
} else
|
|
width = g->desired_width - 2*bp;
|
|
|
|
if ( g->desired_height<=0 ) {
|
|
for ( i=0; i<gl->ltot && i<8; ++i ) {
|
|
height += GTextInfoGetHeight(gl->g.base,gl->ti[i],gl->font);
|
|
}
|
|
if ( i<4 ) {
|
|
int as, ds, ld;
|
|
GDrawWindowFontMetrics(g->base,gl->font,&as, &ds, &ld);
|
|
height += (4-i)*(as+ds);
|
|
}
|
|
} else
|
|
height = g->desired_height - 2*bp;
|
|
if ( inner!=NULL ) {
|
|
inner->x = inner->y = 0;
|
|
inner->width = width;
|
|
inner->height = height;
|
|
}
|
|
if ( outer!=NULL ) {
|
|
outer->x = outer->y = 0;
|
|
outer->width = width + 2*bp;
|
|
outer->height = height + 2*bp;
|
|
}
|
|
}
|
|
|
|
static int glist_FillsWindow(GGadget *g) {
|
|
return( g->prev==NULL &&
|
|
(_GWidgetGetGadgets(g->base)==g ||
|
|
_GWidgetGetGadgets(g->base)==(GGadget *) ((GList *) g)->vsb));
|
|
}
|
|
|
|
struct gfuncs GList_funcs = {
|
|
0,
|
|
sizeof(struct gfuncs),
|
|
|
|
glist_expose,
|
|
glist_mouse,
|
|
glist_key,
|
|
NULL,
|
|
NULL,
|
|
glist_timer,
|
|
NULL,
|
|
|
|
glist_redraw,
|
|
glist_move,
|
|
glist_resize,
|
|
glist_setvisible,
|
|
glist_setenabled,
|
|
glist_getsize,
|
|
_ggadget_getinnersize,
|
|
|
|
GList_destroy,
|
|
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
GListSetFont,
|
|
GListGetFont,
|
|
|
|
GListClear,
|
|
GListSetList,
|
|
GListGetList,
|
|
GListGetListItem,
|
|
GListSelect,
|
|
GListSelectOne,
|
|
GListIsItemSelected,
|
|
GListGetFirstSelPos,
|
|
GListShowPos,
|
|
GListScrollToText,
|
|
GListSetOrderer,
|
|
|
|
GListGetDesiredSize,
|
|
_ggadget_setDesiredSize,
|
|
glist_FillsWindow
|
|
};
|
|
|
|
static GBox list_box = { /* Don't initialize here */ 0 };
|
|
static FontInstance *list_font = NULL;
|
|
static int glist_inited = false;
|
|
|
|
static GTextInfo list_choices[] = {
|
|
{ (unichar_t *) "1", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1 },
|
|
{ (unichar_t *) "2" , NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1},
|
|
{ (unichar_t *) "3" , NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1},
|
|
NULL
|
|
};
|
|
static GGadgetCreateData list_gcd[] = {
|
|
{GListCreate, {{0,0,0,36},NULL,0,0,0,0,0,&list_choices[0],list_choices,gg_visible}},
|
|
{GListCreate, {{0,0,0,36},NULL,0,0,0,0,0,&list_choices[0],list_choices,gg_visible|gg_enabled}}
|
|
};
|
|
static GGadgetCreateData *tarray[] = { GCD_Glue, &list_gcd[0], GCD_Glue, &list_gcd[1], GCD_Glue, NULL, NULL };
|
|
static GGadgetCreateData listhvbox =
|
|
{GHVGroupCreate, {{2,2},NULL,0,0,0,0,0,NULL,(GTextInfo *) tarray,gg_visible|gg_enabled}};
|
|
static GResInfo glist_ri = {
|
|
NULL, &ggadget_ri,NULL, NULL,
|
|
&list_box,
|
|
&list_font,
|
|
&listhvbox,
|
|
NULL,
|
|
N_("List"),
|
|
N_("List"),
|
|
"GList",
|
|
"Gdraw",
|
|
false,
|
|
box_foreground_border_outer
|
|
};
|
|
|
|
static void GListInit() {
|
|
_GGadgetCopyDefaultBox(&list_box);
|
|
list_box.flags |= box_foreground_border_outer;
|
|
list_font = _GGadgetInitDefaultBox("GList.",&list_box,NULL);
|
|
glist_inited = true;
|
|
}
|
|
|
|
static void GListFit(GList *gl) {
|
|
int bp = GBoxBorderWidth(gl->g.base,gl->g.box);
|
|
GRect inner, outer;
|
|
|
|
GListGetDesiredSize(&gl->g,&outer,&inner);
|
|
if ( gl->g.r.width==0 )
|
|
gl->g.r.width = outer.width;
|
|
if ( gl->g.r.height==0 )
|
|
gl->g.r.height = outer.height;
|
|
gl->g.inner = gl->g.r;
|
|
gl->g.inner.x += bp; gl->g.inner.y += bp;
|
|
gl->g.inner.width -= 2*bp; gl->g.inner.height -= 2*bp;
|
|
GListCheckSB(gl);
|
|
}
|
|
|
|
static GList *_GListCreate(GList *gl, struct gwindow *base, GGadgetData *gd,void *data, GBox *def) {
|
|
int same;
|
|
|
|
if ( !glist_inited )
|
|
GListInit();
|
|
gl->g.funcs = &GList_funcs;
|
|
_GGadget_Create(&gl->g,base,gd,data,def);
|
|
gl->font = list_font;
|
|
gl->g.takes_input = gl->g.takes_keyboard = true; gl->g.focusable = true;
|
|
|
|
if ( !(gd->flags & gg_list_internal ) ) {
|
|
gl->ti = GTextInfoArrayFromList(gd->u.list,&gl->ltot);
|
|
gl->freeti = true;
|
|
} else {
|
|
gl->ti = (GTextInfo **) (gd->u.list);
|
|
gl->ltot = GTextInfoArrayCount(gl->ti);
|
|
}
|
|
gl->hmax = GTextInfoGetMaxHeight(gl->g.base,gl->ti,gl->font,&same);
|
|
gl->sameheight = same;
|
|
if ( gd->flags & gg_list_alphabetic ) {
|
|
gl->orderer = GListAlphaCompare;
|
|
GListOrderIt(gl);
|
|
}
|
|
gl->start = gl->end = -1;
|
|
if ( gd->flags & gg_list_multiplesel )
|
|
gl->multiple_sel = true;
|
|
else if ( gd->flags & gg_list_exactlyone ) {
|
|
int sel = GListGetFirstSelPos(&gl->g);
|
|
gl->exactly_one = true;
|
|
if ( sel==-1 ) sel = 0;
|
|
GListClearSel(gl);
|
|
if ( gl->ltot>0 ) gl->ti[sel]->selected = true;
|
|
}
|
|
|
|
GListFit(gl);
|
|
_GGadget_FinalPosition(&gl->g,base,gd);
|
|
|
|
if ( gd->flags & gg_group_end )
|
|
_GGadgetCloseGroup(&gl->g);
|
|
GWidgetIndicateFocusGadget(&gl->g);
|
|
return( gl );
|
|
}
|
|
|
|
GGadget *GListCreate(struct gwindow *base, GGadgetData *gd,void *data) {
|
|
GList *gl = _GListCreate(gcalloc(1,sizeof(GList)),base,gd,data,&list_box);
|
|
|
|
return( &gl->g );
|
|
}
|
|
|
|
static int popup_eh(GWindow popup,GEvent *event) {
|
|
GGadget *owner = GDrawGetUserData(popup);
|
|
|
|
if ( event->type == et_controlevent ) {
|
|
GList *gl = (GList *) (event->u.control.g);
|
|
void (*inform)(GGadget *,int) = (void (*) (GGadget *,int)) GGadgetGetUserData(&gl->g);
|
|
int i;
|
|
for ( i=0; i<gl->ltot; ++i )
|
|
if ( gl->ti[i]->selected )
|
|
break;
|
|
if ( i>=gl->ltot ) i = -1;
|
|
GDrawDestroyWindow(popup);
|
|
(inform)(owner,i);
|
|
} else if ( event->type == et_close ) {
|
|
GGadget *g = GWindowGetFocusGadgetOfWindow(popup);
|
|
void (*inform)(GGadget *,int) = (void (*) (GGadget *,int)) GGadgetGetUserData(g);
|
|
GDrawDestroyWindow(popup);
|
|
_GWidget_ClearPopupOwner(owner);
|
|
_GWidget_ClearGrabGadget(owner);
|
|
(inform)(owner,-1);
|
|
} else if ( event->type == et_destroy ) {
|
|
_GWidget_ClearPopupOwner(owner);
|
|
_GWidget_ClearGrabGadget(owner);
|
|
}
|
|
return( true );
|
|
}
|
|
|
|
static void GListPopupFigurePos(GGadget *owner,GTextInfo **ti,GRect *pos) {
|
|
int width, height, width1, maxh;
|
|
int i;
|
|
GWindow root = GDrawGetRoot(GDrawGetDisplayOfWindow(owner->base));
|
|
GRect rsize, rootsize;
|
|
int bp;
|
|
GPoint pt;
|
|
|
|
if ( !glist_inited )
|
|
GListInit();
|
|
GDrawGetSize(GDrawGetRoot(GDrawGetDisplayOfWindow(owner->base)),&rootsize);
|
|
maxh = 2*rootsize.height/3;
|
|
width = GTextInfoGetMaxWidth(owner->base,ti,list_font);
|
|
height = 0;
|
|
for ( i=0; height<maxh && (ti[i]->text!=NULL || ti[i]->image!=NULL || ti[i]->line); ++i )
|
|
height += GTextInfoGetHeight(owner->base,ti[i],list_font);
|
|
if ( ti[i]->text!=NULL || ti[i]->image!=NULL || ti[i]->line ) /* Need a scroll bar if more */
|
|
width += GDrawPointsToPixels(owner->base,_GScrollBar_Width) +
|
|
GDrawPointsToPixels(owner->base,1);
|
|
bp = GBoxBorderWidth(owner->base,&list_box);
|
|
width += 2*bp; height += 2*bp;
|
|
if ( (width1 = width)<owner->r.width ) width = owner->r.width;
|
|
|
|
GDrawGetSize(root,&rsize);
|
|
if ( width>rsize.width ) width = rsize.width;
|
|
if ( height>rsize.height ) height = rsize.height;
|
|
pt.x = owner->r.x; pt.y = owner->r.y+owner->r.height;
|
|
GDrawTranslateCoordinates(owner->base,root,&pt);
|
|
if ( pt.y+height > rsize.height ) {
|
|
pt.x = owner->r.x; pt.y = owner->r.y-height;
|
|
GDrawTranslateCoordinates(owner->base,root,&pt);
|
|
if ( pt.y<0 ) {
|
|
pt.y = 0;
|
|
/* Ok, it will overlap the base widget. not that good an idea */
|
|
if ( pt.x+owner->r.width+width+3<rsize.width )
|
|
pt.x += owner->r.width+3;
|
|
else if ( pt.x-width-3>=0 )
|
|
pt.x -= width+3;
|
|
else
|
|
/* But there doesn't seem much we can do about it if we get here */;
|
|
}
|
|
}
|
|
pos->y = pt.y;
|
|
|
|
if ( pt.x+width > rsize.width ) width = width1;
|
|
if ( pt.x+width > rsize.width ) {
|
|
pt.x = owner->r.x+owner->r.width-width; pt.y = 0;
|
|
GDrawTranslateCoordinates(owner->base,root,&pt);
|
|
if ( pt.x<0 )
|
|
pt.x = 0;
|
|
}
|
|
pos->x = pt.x;
|
|
pos->width = width;
|
|
pos->height = height;
|
|
}
|
|
|
|
GWindow GListPopupCreate(GGadget *owner,void (*inform)(GGadget *,int), GTextInfo **ti) {
|
|
GWindow popup;
|
|
GWindowAttrs pattrs;
|
|
GDisplay *disp = GDrawGetDisplayOfWindow(owner->base);
|
|
GRect pos;
|
|
GGadgetData gd;
|
|
GList *gl;
|
|
int i;
|
|
GEvent e;
|
|
|
|
if ( ti==NULL )
|
|
return(NULL);
|
|
|
|
GDrawPointerUngrab(disp);
|
|
GDrawGetPointerPosition(owner->base,&e);
|
|
|
|
pattrs.mask = wam_events|wam_nodecor|wam_positioned|wam_cursor|wam_transient|wam_verytransient;
|
|
pattrs.event_masks = -1;
|
|
pattrs.nodecoration = true;
|
|
pattrs.positioned = true;
|
|
pattrs.cursor = ct_pointer;
|
|
pattrs.transient = GWidgetGetTopWidget(owner->base);
|
|
|
|
GListPopupFigurePos(owner,ti,&pos);
|
|
popup = GDrawCreateTopWindow(disp,&pos,popup_eh,owner,&pattrs);
|
|
|
|
memset(&gd,'\0',sizeof(gd));
|
|
gd.pos.x = gd.pos.y = 0;
|
|
gd.pos.width = pos.width; gd.pos.height = pos.height;
|
|
gd.u.list = (GTextInfo *) ti;
|
|
gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels | gg_list_internal |
|
|
gg_pos_use0;
|
|
gl = (GList *) GListCreate(popup,&gd,(void *) inform);
|
|
for ( i=0; ti[i]->text!=NULL || ti[i]->image!=NULL || ti[i]->line ; ++i )
|
|
if ( ti[i]->selected ) {
|
|
GListScrollBy(gl,i,0);
|
|
break;
|
|
}
|
|
GDrawSetVisible(popup,true);
|
|
GDrawPointerGrab(popup);
|
|
_GWidget_SetGrabGadget(&gl->g);
|
|
if ( e.u.mouse.state&(ksm_button1|ksm_button2|ksm_button3) )
|
|
gl->parentpressed = true;
|
|
gl->ispopup = true;
|
|
_GWidget_SetPopupOwner(owner);
|
|
return( popup );
|
|
}
|
|
|
|
int GListIndexFromY(GGadget *g,int y) {
|
|
return( GListIndexFromPos( (GList *) g, y ));
|
|
}
|
|
|
|
void GListSetSBAlwaysVisible(GGadget *g,int always) {
|
|
((GList *) g)->always_show_sb = always;
|
|
}
|
|
|
|
void GListSetPopupCallback(GGadget *g,void (*callback)(GGadget *,int)) {
|
|
((GList *) g)->popup_callback = callback;
|
|
}
|
|
|
|
GResInfo *_GListRIHead(void) {
|
|
int as,ds,ld;
|
|
|
|
if ( !glist_inited )
|
|
GListInit();
|
|
/* bp = GBoxBorderWidth(GDrawGetRoot(NULL),&list_box);*/ /* This gives bizarre values */
|
|
GDrawFontMetrics(list_font,&as, &ds, &ld); /* I don't have a window yet... */
|
|
list_gcd[0].gd.pos.height = list_gcd[1].gd.pos.height = 2*(as+ds)+4;
|
|
return( &glist_ri );
|
|
}
|