LCOV - code coverage report
Current view: top level - gdraw - glist.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 800 0.0 %
Date: 2017-08-04 Functions: 0 55 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2000-2012 by George Williams */
       2             : /*
       3             :  * Redistribution and use in source and binary forms, with or without
       4             :  * modification, are permitted provided that the following conditions are met:
       5             : 
       6             :  * Redistributions of source code must retain the above copyright notice, this
       7             :  * list of conditions and the following disclaimer.
       8             : 
       9             :  * Redistributions in binary form must reproduce the above copyright notice,
      10             :  * this list of conditions and the following disclaimer in the documentation
      11             :  * and/or other materials provided with the distribution.
      12             : 
      13             :  * The name of the author may not be used to endorse or promote products
      14             :  * derived from this software without specific prior written permission.
      15             : 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      17             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      18             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      19             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      20             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      21             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      22             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      23             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      24             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      25             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : #include "gdraw.h"
      28             : #include "gkeysym.h"
      29             : #include "ggadgetP.h"
      30             : #include "gwidget.h"
      31             : #include "ustring.h"
      32             : #include "gwidget.h"
      33             : 
      34             : static int GListTypeTime = 500;                 /* half a second between keystrokes */
      35             : static int GListScrollTime = 500;               /* half a second between scrolls when mouse out of listbox */
      36             : 
      37           0 : static void GListSelected(GList *l,int frommouse,int index) {
      38             :     GEvent e;
      39             : 
      40           0 :     e.type = et_controlevent;
      41           0 :     e.w = l->g.base;
      42           0 :     e.u.control.subtype = et_listselected;
      43           0 :     e.u.control.g = &l->g;
      44           0 :     e.u.control.u.list.from_mouse = frommouse;
      45           0 :     e.u.control.u.list.changed_index = index;
      46           0 :     if ( l->g.handle_controlevent != NULL )
      47           0 :         (l->g.handle_controlevent)(&l->g,&e);
      48             :     else
      49           0 :         GDrawPostEvent(&e);
      50           0 : }
      51             : 
      52           0 : static void GListDoubleClick(GList *l,int frommouse,int index) {
      53             :     GEvent e;
      54             : 
      55           0 :     e.type = et_controlevent;
      56           0 :     e.w = l->g.base;
      57           0 :     e.u.control.subtype = et_listdoubleclick;
      58           0 :     e.u.control.g = &l->g;
      59           0 :     e.u.control.u.list.from_mouse = frommouse;
      60           0 :     e.u.control.u.list.changed_index = index;
      61           0 :     if ( l->g.handle_controlevent != NULL )
      62           0 :         (l->g.handle_controlevent)(&l->g,&e);
      63             :     else
      64           0 :         GDrawPostEvent(&e);
      65           0 : }
      66             : 
      67           0 : static void GListClose(GList *l) {
      68             :     GEvent e;
      69             : 
      70           0 :     e.type = et_close;
      71           0 :     e.w = l->g.base;
      72           0 :     if ( l->g.handle_controlevent != NULL )
      73           0 :         (l->g.handle_controlevent)(&l->g,&e);
      74             :     else
      75           0 :         GDrawPostEvent(&e);
      76           0 : }
      77             : 
      78           0 : static int GListTopInWindow(GList *gl,int last) {
      79             :     /* If we want to display last at the bottom of our list, then what line */
      80             :     /*  do we display at the top? */
      81           0 :     int32 height = gl->g.inner.height, temp;
      82             :     int l;
      83             : 
      84           0 :     for ( l=last; l>=0; --l ) {
      85           0 :         temp = GTextInfoGetHeight(gl->g.base,gl->ti[l],gl->font);
      86           0 :         if ( height<temp )
      87           0 : return( l==last?last:l+1 );             /* if we can't even fit one line on, pretend it fits */
      88           0 :         height -= temp;
      89             :     }
      90           0 : return( 0 );
      91             : }
      92             : 
      93           0 : static int GListLinesInWindow(GList *gl,int first) {
      94             :     /* Ok, the first line displayed is "first", how many others do we have */
      95             :     /*  room for? */
      96           0 :     int32 height = gl->g.inner.height, temp;
      97           0 :     int l, lcnt=0;
      98             : 
      99           0 :     for ( l=first; l<gl->ltot; ++l ) {
     100           0 :         temp = GTextInfoGetHeight(gl->g.base,gl->ti[l],gl->font);
     101           0 :         if ( height<temp )
     102           0 : return( l==first?1:lcnt );              /* if we can't even fit one line on, pretend it fits */
     103           0 :         height -= temp;
     104           0 :         ++lcnt;
     105             :     }
     106           0 :     if ( height>0 ) {
     107           0 :         if ( gl->fh==0 ) {
     108             :             int as, ds, ld;
     109           0 :             GDrawWindowFontMetrics(gl->g.base,gl->font,&as, &ds, &ld);
     110           0 :             gl->fh = as+ds;
     111           0 :             gl->as = as;
     112             :         }
     113           0 :         lcnt += height/gl->fh;
     114             :     }
     115           0 :     if ( lcnt==0 )
     116           0 :         lcnt=1;
     117           0 : return( lcnt );
     118             : }
     119             : 
     120           0 : static int GListAlphaCompare(const void *v1, const void *v2) {
     121           0 :     GTextInfo * const *pt1 = v1, * const *pt2 = v2;
     122           0 : return( GTextInfoCompare(*pt1,*pt2));
     123             : }
     124             : 
     125           0 : static void GListOrderIt(GList *gl) {
     126           0 :     qsort(gl->ti,gl->ltot,sizeof(GTextInfo *),gl->orderer);
     127           0 :     if ( gl->backwards ) {
     128             :         int i;
     129             :         GTextInfo *ti;
     130           0 :         for ( i=0; i<gl->ltot/2; ++i ) {
     131           0 :             ti = gl->ti[i];
     132           0 :             gl->ti[i] = gl->ti[gl->ltot-1-i];
     133           0 :             gl->ti[gl->ltot-1-i] = ti;
     134             :         }
     135             :     }
     136           0 : }
     137             : 
     138           0 : static void GListClearSel(GList *gl) {
     139             :     int i;
     140             : 
     141           0 :     for ( i=0; (i<gl->ltot && gl->ti[i]!=NULL); ++i )
     142           0 :         gl->ti[i]->selected = false;
     143           0 : }
     144             : 
     145           0 : static int GListAnyOtherSels(GList *gl, int pos) {
     146             :     int i;
     147             : 
     148           0 :     for ( i=0; i<gl->ltot; ++i )
     149           0 :         if ( gl->ti[i]->selected && i!=pos )
     150           0 : return( true );
     151             : 
     152           0 : return( false );
     153             : }
     154             : 
     155           0 : static int32 GListGetFirstSelPos(GGadget *g) {
     156             :     int i;
     157           0 :     GList *gl = (GList *) g;
     158             : 
     159           0 :     for ( i=0; i<gl->ltot; ++i )
     160           0 :         if ( gl->ti[i]->selected )
     161           0 : return( i );
     162             : 
     163           0 : return( -1 );
     164             : }
     165             : 
     166           0 : static void GListSelect(GGadget *g, int32 pos, int32 sel) {
     167           0 :     GList *gl = (GList *) g;
     168             :     int i;
     169             : 
     170           0 :     if ( pos==-1 && (gl->multiple_sel || (!sel && !gl->exactly_one)) ) {
     171             :         /* Select/deselect all */
     172           0 :         for ( i=0; i<gl->ltot; ++i )
     173           0 :             gl->ti[i]->selected = sel;
     174           0 :         _ggadget_redraw(g);
     175           0 : return;
     176             :     }
     177             : 
     178           0 :     if ( pos>=gl->ltot || pos<0 )
     179           0 : return;
     180           0 :     if ( gl->exactly_one && !sel )
     181           0 : return;
     182           0 :     if ( !gl->multiple_sel && sel )
     183           0 :         GListClearSel(gl);
     184           0 :     if ( gl->ltot>0 ) {
     185           0 :         gl->ti[pos]->selected = sel;
     186           0 :         _ggadget_redraw(g);
     187             :     }
     188             : }
     189             : 
     190           0 : static void GListSelectOne(GGadget *g, int32 pos) {
     191           0 :     GList *gl = (GList *) g;
     192             : 
     193           0 :     GListClearSel(gl);
     194           0 :     if ( pos>=gl->ltot ) pos = gl->ltot-1;
     195           0 :     if ( pos<0 ) pos = 0;
     196           0 :     if ( gl->ltot>0 ) {
     197           0 :         gl->ti[pos]->selected = true;
     198           0 :         _ggadget_redraw(g);
     199             :     }
     200           0 : }
     201             : 
     202           0 : static int32 GListIsItemSelected(GGadget *g, int32 pos) {
     203           0 :     GList *gl = (GList *) g;
     204             : 
     205           0 :     if ( pos>=gl->ltot )
     206           0 : return( false );
     207           0 :     if ( pos<0 )
     208           0 : return( false );
     209           0 :     if ( gl->ltot>0 )
     210           0 : return( gl->ti[pos]->selected );
     211             : 
     212           0 : return( false );
     213             : }
     214             : 
     215           0 : static void GListExpandSelection(GList *gl,int pos) {
     216             :     int i;
     217             : 
     218           0 :     if ( gl->start!=65535 ) {
     219           0 :         if ( gl->start<gl->end )
     220           0 :             for ( i=gl->start; i<=gl->end; ++i )
     221           0 :                 gl->ti[i]->selected = false;
     222             :         else
     223           0 :             for ( i=gl->start; i>=gl->end; --i )
     224           0 :                 gl->ti[i]->selected = false;
     225             :     } else
     226           0 :         gl->start = pos;
     227           0 :     gl->end = pos;
     228           0 :     if ( gl->start<gl->end )
     229           0 :         for ( i=gl->start; i<=gl->end; ++i )
     230           0 :             gl->ti[i]->selected = true;
     231             :     else
     232           0 :         for ( i=gl->start; i>=gl->end; --i )
     233           0 :             gl->ti[i]->selected = true;
     234           0 : }
     235             : 
     236           0 : static int GListIndexFromPos(GList *gl,int y) {
     237             :     int i, height;
     238             : 
     239           0 :     y -= gl->g.inner.y;
     240           0 :     if ( y<0 ) y=0;
     241           0 :     if ( y>=gl->g.inner.height ) y = gl->g.inner.height-1;
     242           0 :     for ( i=gl->loff, height=0; i<gl->ltot; ++i ) {
     243           0 :         int temp = GTextInfoGetHeight(gl->g.base,gl->ti[i],gl->font);
     244           0 :         if ( height+temp>y )
     245           0 :     break;
     246           0 :         height += temp;
     247             :     }
     248           0 :     if ( i==gl->ltot )
     249           0 : return( -1 );
     250           0 :     if ( gl->ti[i]->disabled )
     251           0 : return( -1 );
     252           0 : return( i );
     253             : }
     254             : 
     255           0 : static void GListScrollBy(GList *gl,int loff,int xoff) {
     256           0 :     int top = GListTopInWindow(gl,gl->ltot-1);
     257             :     int ydiff, i;
     258             : 
     259           0 :     if ( gl->loff + loff < 0 )
     260           0 :         loff = -gl->loff;
     261           0 :     else if ( gl->loff + loff > top )
     262           0 :         loff = top-gl->loff;
     263           0 :     if ( xoff+gl->xoff<0 )
     264           0 :         xoff = -gl->xoff;
     265           0 :     else if ( xoff+gl->xoff+gl->g.inner.width > gl->xmax ) {
     266           0 :         xoff = gl->xmax-gl->g.inner.width-gl->xoff;
     267           0 :         if ( xoff<0 ) xoff = 0;
     268             :     }
     269           0 :     if ( loff == 0 && xoff==0 )
     270           0 : return;
     271             : 
     272           0 :     ydiff = 0;
     273           0 :     if ( loff>0 ) {
     274           0 :         for ( i=0; i<loff && ydiff<gl->g.inner.height; ++i )
     275           0 :             ydiff += GTextInfoGetHeight(gl->g.base,gl->ti[i+gl->loff],gl->font);
     276           0 :     } else if ( loff<0 ) {
     277           0 :         for ( i=loff; i<0 && -ydiff<gl->g.inner.height; ++i )
     278           0 :             ydiff -= GTextInfoGetHeight(gl->g.base,gl->ti[i+gl->loff],gl->font);
     279             :     }
     280           0 :     if ( !GDrawIsVisible(gl->g.base))
     281           0 : return;
     282           0 :     GDrawForceUpdate(gl->g.base);
     283           0 :     gl->loff += loff; gl->xoff += xoff;
     284           0 :     if ( ydiff>=gl->g.inner.height || -ydiff >= gl->g.inner.height )
     285           0 :         _ggadget_redraw(&gl->g);
     286           0 :     else if ( ydiff!=0 || xoff!=0 )
     287           0 :         GDrawScroll(gl->g.base,&gl->g.inner,xoff,ydiff);
     288           0 :     if ( loff!=0 && gl->vsb!=NULL )
     289           0 :         GScrollBarSetPos(&gl->vsb->g,gl->loff);
     290             : }
     291             : 
     292           0 : static int GListFindPosition(GList *gl,unichar_t *text) {
     293           0 :     GTextInfo temp, *ptemp=&temp;
     294             :     int i, order;
     295             : 
     296           0 :     if ( gl->orderer!=NULL ) {
     297           0 :         memset(&temp,'\0',sizeof(temp));
     298           0 :         temp.text = text;
     299             : 
     300             :         /* I don't think I need to write a binary search here... */
     301           0 :         for ( i=0; i<gl->ltot; ++i ) {
     302           0 :             order = (gl->orderer)(&ptemp,&gl->ti[i]);
     303           0 :             if (( order<= 0 && !gl->backwards ) || ( order>=0 && gl->backwards ))
     304           0 : return( i );
     305             :         }
     306           0 : return( 0 );
     307             :     } else {
     308           0 :         for ( i=0; i<gl->ltot; ++i ) {
     309           0 :             if (u_strmatch(text,gl->ti[i]->text)==0 )
     310           0 : return( i );
     311             :         }
     312             :     }
     313           0 : return( 0 );
     314             : }
     315             : 
     316           0 : static int GListAdjustPos(GGadget *g,int pos) {
     317           0 :     GList *gl = (GList *) g;
     318           0 :     int newoff = gl->loff;
     319             : 
     320           0 :     if ( pos<gl->loff ) {
     321           0 :         if (( newoff = pos-1)<0 ) newoff = 0;
     322           0 :         if ( GListLinesInWindow(gl,newoff)<2 )
     323           0 :             newoff = pos;
     324           0 :     } else if ( pos >= gl->loff + GListLinesInWindow(gl,gl->loff) ) {
     325           0 :         newoff = GListTopInWindow(gl,pos);
     326           0 :         if ( pos!=gl->ltot-1 && GListLinesInWindow(gl,newoff+1)>=2 )
     327           0 :             ++newoff;
     328             :     }
     329           0 : return( newoff );
     330             : }
     331             : 
     332           0 : static void GListShowPos(GGadget *g,int32 pos) {
     333           0 :     GList *gl = (GList *) g;
     334           0 :     int newoff = GListAdjustPos(g,pos);
     335           0 :     if ( newoff!=gl->loff )
     336           0 :         GListScrollBy(gl,newoff-gl->loff,0);
     337           0 : }
     338             : 
     339           0 : static void GListScrollToText(GGadget *g,const unichar_t *text,int32 sel) {
     340           0 :     GList *gl = (GList *) g;
     341             :     int pos;
     342             : 
     343           0 :     pos = GListFindPosition(gl,(unichar_t *) text);
     344           0 :     if ( sel && pos<gl->ltot ) {
     345           0 :         GListClearSel(gl);
     346           0 :         if ( gl->exactly_one || u_strmatch(text,gl->ti[pos]->text)==0 )
     347           0 :             gl->ti[pos]->selected = true;
     348             :     }
     349           0 :     gl->loff = GListAdjustPos(g,pos);
     350           0 :     if ( gl->vsb!=NULL )
     351           0 :         GScrollBarSetPos(&gl->vsb->g,gl->loff);
     352           0 :     _ggadget_redraw(g);
     353           0 : }
     354             : 
     355           0 : static void GListSetOrderer(GGadget *g,int (*orderer)(const void *, const void *)) {
     356           0 :     GList *gl = (GList *) g;
     357             : 
     358           0 :     gl->orderer = orderer;
     359           0 :     if ( orderer!=NULL ) {
     360           0 :         GListOrderIt(gl);
     361           0 :         GListScrollBy(gl,-gl->loff,-gl->xoff);
     362           0 :         _ggadget_redraw(&gl->g);
     363             :     }
     364           0 : }
     365             : 
     366             : static int glist_scroll(GGadget *g, GEvent *event);
     367           0 : static void GListCheckSB(GList *gl) {
     368           0 :     if ( gl->vsb==NULL ) {
     369             :         GGadgetData gd;
     370           0 :         memset(&gd,'\0',sizeof(gd));
     371           0 :         gd.pos.y = gl->g.r.y; gd.pos.height = gl->g.r.height;
     372           0 :         gd.pos.width = GDrawPointsToPixels(gl->g.base,_GScrollBar_Width);
     373           0 :         gd.pos.x = gl->g.r.x+gl->g.r.width - gd.pos.width;
     374           0 :         gd.flags = gg_visible|gg_enabled|gg_pos_in_pixels|gg_sb_vert|gg_pos_use0;
     375           0 :         gd.handle_controlevent = glist_scroll;
     376           0 :         gl->vsb = (GScrollBar *) GScrollBarCreate(gl->g.base,&gd,gl);
     377           0 :         gl->vsb->g.contained = true;
     378             : 
     379           0 :         gd.pos.width += GDrawPointsToPixels(gl->g.base,1);
     380           0 :         gl->g.r.width -= gd.pos.width;
     381           0 :         gl->g.inner.width -= gd.pos.width;
     382             :     }
     383           0 :     if ( gl->always_show_sb || GListLinesInWindow(gl,0)<gl->ltot ) {
     384           0 :         if ( gl->vsb->g.state == gs_invisible ) {
     385           0 :             int wid = gl->vsb->g.r.width + GDrawPointsToPixels(gl->g.base,1);
     386           0 :             gl->vsb->g.state = gs_enabled;
     387           0 :             gl->g.r.width -= wid;
     388           0 :             gl->g.inner.width -= wid;
     389             :         }
     390           0 :         GScrollBarSetBounds(&gl->vsb->g,0,gl->ltot,GListLinesInWindow(gl,0));
     391           0 :         GScrollBarSetPos(&gl->vsb->g,gl->loff);
     392             :     } else {
     393           0 :         if ( gl->vsb->g.state != gs_invisible ) {
     394           0 :             int wid = gl->vsb->g.r.width + GDrawPointsToPixels(gl->g.base,1);
     395           0 :             gl->vsb->g.state = gs_invisible;
     396           0 :             gl->g.r.width += wid;
     397           0 :             gl->g.inner.width += wid;
     398             :         }
     399             :     }
     400           0 : }
     401             : 
     402           0 : static int GListFindXMax(GList *gl) {
     403           0 :     int i, width=0, temp;
     404             : 
     405           0 :     for ( i=0; i<gl->ltot; ++i ) {
     406           0 :         temp = GTextInfoGetWidth(gl->g.base,gl->ti[i],gl->font);
     407           0 :         if ( temp>width ) width=temp;
     408             :     }
     409           0 :     gl->xmax = width;
     410           0 : return( width );
     411             : }
     412             : 
     413           0 : static void GListSetList(GGadget *g,GTextInfo **ti,int32 docopy) {
     414           0 :     GList *gl = (GList *) g;
     415             :     int same;
     416             : 
     417           0 :     GTextInfoArrayFree(gl->ti);
     418           0 :     if ( docopy || ti==NULL )
     419           0 :         ti = GTextInfoArrayCopy(ti);
     420           0 :     gl->ti = ti;
     421           0 :     gl->ltot = GTextInfoArrayCount(ti);
     422           0 :     if ( gl->orderer!=NULL )
     423           0 :         GListOrderIt(gl);
     424           0 :     gl->loff = gl->xoff = 0;
     425           0 :     gl->hmax = GTextInfoGetMaxHeight(g->base,ti,gl->font,&same);
     426           0 :     gl->sameheight = same;
     427           0 :     GListCheckSB(gl);
     428           0 :     _ggadget_redraw(&gl->g);
     429           0 : }
     430             : 
     431           0 : static void GListClear(GGadget *g) {
     432           0 :     GListSetList(g,NULL,true);
     433           0 : }
     434             : 
     435           0 : static GTextInfo **GListGetList(GGadget *g,int32 *len) {
     436           0 :     GList *gl = (GList *) g;
     437           0 :     if ( len!=NULL ) *len = gl->ltot;
     438           0 : return( gl->ti );
     439             : }
     440             : 
     441           0 : static GTextInfo *GListGetListItem(GGadget *g,int32 pos) {
     442           0 :     GList *gl = (GList *) g;
     443           0 :     if ( pos<0 || pos>=gl->ltot )
     444           0 : return( NULL );
     445             : 
     446           0 : return(gl->ti[pos]);
     447             : }
     448             : 
     449           0 : static int glist_expose(GWindow pixmap, GGadget *g, GEvent *event) {
     450           0 :     GList *gl = (GList *) g;
     451             :     GRect old0, old1, old2;
     452             :     Color fg, dfg;
     453             :     int y, l, ymax;
     454             : 
     455           0 :     if ( g->state == gs_invisible )
     456           0 : return( false );
     457             : 
     458           0 :     GDrawPushClip(pixmap,&event->u.expose.rect,&old0);
     459           0 :     GDrawPushClip(pixmap,&g->r,&old1);
     460             : 
     461           0 :     GBoxDrawBackground(pixmap,&g->r,g->box, g->state,false);
     462           0 :     if ( g->box->border_type!=bt_none ||
     463           0 :             (g->box->flags&(box_foreground_border_inner|box_foreground_border_outer|box_active_border_inner))!=0 ) {
     464           0 :         GBoxDrawBorder(pixmap,&g->r,g->box,g->state,false);
     465             : 
     466           0 :         GDrawPushClip(pixmap,&g->inner,&old2);
     467             :     }
     468             : 
     469           0 :     fg = g->state==gs_disabled?g->box->disabled_foreground:g->box->main_foreground;
     470           0 :     dfg = g->box->disabled_foreground;
     471           0 :     y = g->inner.y;
     472           0 :     ymax = g->inner.y+g->inner.height;
     473           0 :     if ( ymax>event->u.expose.rect.y+event->u.expose.rect.height )
     474           0 :         ymax = event->u.expose.rect.y+event->u.expose.rect.height;
     475           0 :     for ( l = gl->loff; y<ymax && l<gl->ltot; ++l ) {
     476           0 :         if ( y+gl->hmax > event->u.expose.rect.y )
     477           0 :             y += GTextInfoDraw(pixmap,g->inner.x-gl->xoff,y,gl->ti[l],
     478           0 :                     gl->font,gl->ti[l]->disabled?dfg:fg,g->box->active_border,
     479             :                     ymax);
     480           0 :         else if ( gl->sameheight )
     481           0 :             y += gl->hmax;
     482             :         else
     483           0 :             y += GTextInfoGetHeight(pixmap,gl->ti[l],gl->font);
     484             :     }
     485           0 :     if ( g->box->border_type!=bt_none ||
     486           0 :             (g->box->flags&(box_foreground_border_inner|box_foreground_border_outer|box_active_border_inner))!=0 )
     487           0 :         GDrawPopClip(pixmap,&old2);
     488           0 :     GDrawPopClip(pixmap,&old1);
     489           0 :     GDrawPopClip(pixmap,&old0);
     490           0 : return( true );
     491             : }
     492             : 
     493           0 : static void glist_scroll_selbymouse(GList *gl, GEvent *event) {
     494           0 :     int loff=0, xoff=0, pos;
     495             : 
     496           0 :     if ( event->u.mouse.y<gl->g.inner.y ) {
     497           0 :         if ( gl->loff>0 ) loff = -1;
     498           0 :     } else if ( event->u.mouse.y >= gl->g.inner.y+gl->g.inner.height ) {
     499           0 :         int top = GListTopInWindow(gl,gl->ltot-1);
     500           0 :         if ( gl->loff<top ) loff = 1;
     501             :     }
     502           0 :     if ( event->u.mouse.x<gl->g.inner.x ) {
     503           0 :         xoff = -GDrawPointsToPixels(gl->g.base,6);
     504           0 :     } else if ( event->u.mouse.x >= gl->g.inner.x+gl->g.inner.width ) {
     505           0 :         xoff = GDrawPointsToPixels(gl->g.base,6);
     506             :     }
     507           0 :     GListScrollBy(gl,loff,xoff);
     508           0 :     pos = GListIndexFromPos(gl,event->u.mouse.y);
     509           0 :     if ( pos==-1 || pos == gl->end )
     510             :         /* Do Nothing, nothing selectable */;
     511           0 :     else if ( !gl->multiple_sel ) {
     512           0 :         GListClearSel(gl);
     513           0 :         gl->ti[pos]->selected = true;
     514           0 :         gl->start = gl->end = pos;
     515           0 :         _ggadget_redraw(&gl->g);
     516             :     } else {
     517           0 :         GListExpandSelection(gl,pos);
     518           0 :         gl->end = pos;
     519           0 :         _ggadget_redraw(&gl->g);
     520             :     }
     521           0 : }
     522             : 
     523           0 : static int glist_mouse(GGadget *g, GEvent *event) {
     524           0 :     GList *gl = (GList *) g;
     525             :     int pos;
     526             : 
     527           0 :     if ( !g->takes_input || (g->state!=gs_active && g->state!=gs_enabled && g->state!=gs_focused))
     528           0 : return( false );
     529             : 
     530           0 :     if ( event->type == et_crossing )
     531           0 : return( false );
     532           0 :     if (( event->type==et_mouseup || event->type==et_mousedown ) &&
     533           0 :             (event->u.mouse.button>=4 && event->u.mouse.button<=7)) {
     534           0 :         if ( gl->vsb!=NULL )
     535           0 : return( GGadgetDispatchEvent(&gl->vsb->g,event));
     536             :         else
     537           0 : return( true );
     538             :     }
     539           0 :     if ( event->type==et_mousemove && !gl->pressed && !gl->parentpressed ) {
     540           0 :         if ( GGadgetWithin(g,event->u.mouse.x,event->u.mouse.y) ) {
     541           0 :             if ( gl->popup_callback!=NULL )
     542           0 :                 (gl->popup_callback)(g,GListIndexFromPos(gl,event->u.mouse.y));
     543           0 :             else if ( g->popup_msg )
     544           0 :                 GGadgetPreparePopup(g->base,g->popup_msg);
     545             :         }
     546           0 : return( true );
     547           0 :     } else if ( event->type==et_mouseup && gl->parentpressed /* &&
     548             :             !GGadgetInnerWithin(&gl->g,event->u.mouse.x,event->u.mouse.y)*/ ) {
     549           0 :         gl->parentpressed = false;
     550           0 :         GDrawPointerUngrab(GDrawGetDisplayOfWindow(gl->g.base));
     551           0 :     } else if ( event->type==et_mousemove && gl->parentpressed &&
     552           0 :             GGadgetInnerWithin(&gl->g,event->u.mouse.x,event->u.mouse.y)) {
     553           0 :         if ( gl->pressed == NULL )
     554           0 :             gl->pressed = GDrawRequestTimer(g->base,GListScrollTime,GListScrollTime,NULL);
     555           0 :         GDrawPointerUngrab(GDrawGetDisplayOfWindow(gl->g.base));
     556           0 :         gl->parentpressed = false;
     557           0 :         glist_scroll_selbymouse(gl,event);
     558           0 : return( true );
     559           0 :     } else if ( event->type==et_mousemove && gl->pressed ) {
     560           0 :         glist_scroll_selbymouse(gl,event);
     561           0 : return( true );
     562           0 :     } else if ( event->type==et_mousedown ) {
     563           0 :         if ( gl->pressed == NULL )
     564           0 :             gl->pressed = GDrawRequestTimer(g->base,GListScrollTime,GListScrollTime,NULL);
     565           0 :         pos = GListIndexFromPos(gl,event->u.mouse.y);
     566           0 :         if ( pos==-1 )
     567           0 : return( true ); /* Do Nothing, nothing selectable */
     568           0 :         else if ( !gl->exactly_one && gl->ti[pos]->selected &&
     569           0 :                 (event->u.mouse.state&(ksm_control|ksm_shift))) {
     570           0 :             gl->ti[pos]->selected = false;
     571           0 :             gl->start = gl->end = 0xffff;
     572           0 :         } else if ( !gl->multiple_sel ||
     573           0 :                 (!gl->ti[pos]->selected && !(event->u.mouse.state&(ksm_control|ksm_shift)))) {
     574           0 :             GListClearSel(gl);
     575           0 :             gl->ti[pos]->selected = true;
     576           0 :             gl->start = gl->end = pos;
     577           0 :         } else if ( event->u.mouse.state&ksm_control ||
     578           0 :                 ((event->u.mouse.state&ksm_shift) && gl->ti[pos]->selected)) {
     579           0 :             gl->ti[pos]->selected = !gl->ti[pos]->selected;
     580           0 :             gl->start = gl->end = pos;
     581           0 :         } else if ( event->u.mouse.state&ksm_shift ) {
     582           0 :             GListExpandSelection(gl,pos);
     583             :         } else {
     584           0 :             gl->ti[pos]->selected = true;
     585           0 :             gl->start = gl->end = pos;
     586             :         }
     587           0 :         _ggadget_redraw(&gl->g);
     588           0 :     } else if ( event->type==et_mouseup && gl->pressed ) {
     589           0 :         GDrawCancelTimer(gl->pressed); gl->pressed = NULL;
     590           0 :         if ( GGadgetInnerWithin(&gl->g,event->u.mouse.x,event->u.mouse.y) ) {
     591           0 :             pos = GListIndexFromPos(gl,event->u.mouse.y);
     592           0 :             if ( !(event->u.mouse.state&(ksm_control|ksm_shift)) || gl->start!=0xffff )
     593           0 :                 glist_scroll_selbymouse(gl,event);
     594           0 :             if ( event->u.mouse.clicks==2 )
     595           0 :                 GListDoubleClick(gl,true,pos);
     596             :             else
     597           0 :                 GListSelected(gl,true,pos);
     598             :         }
     599             :     } else
     600           0 : return( false );
     601             : 
     602           0 : return( true );
     603             : }
     604             : 
     605           0 : static int glist_key(GGadget *g, GEvent *event) {
     606           0 :     GList *gl = (GList *) g;
     607           0 :     uint16 keysym = event->u.chr.keysym;
     608           0 :     int sofar_pos = gl->sofar_pos;
     609           0 :     int loff, xoff, sel=-1;
     610           0 :     int refresh = false;
     611             : 
     612           0 :     if ( event->type == et_charup )
     613           0 : return( false );
     614           0 :     if ( !g->takes_input || (g->state!=gs_enabled && g->state!=gs_active && g->state!=gs_focused ))
     615           0 : return(false );
     616             : 
     617           0 :     if ( gl->ispopup && event->u.chr.keysym == GK_Return ) {
     618           0 :         GListDoubleClick(gl,false,-1);
     619           0 : return( true );
     620           0 :     } else if ( gl->ispopup && event->u.chr.keysym == GK_Escape ) {
     621           0 :         GListClose(gl);
     622           0 : return( true );
     623             :     }
     624             : 
     625           0 :     if ( event->u.chr.keysym == GK_Return || event->u.chr.keysym == GK_Tab ||
     626           0 :             event->u.chr.keysym == GK_BackTab || event->u.chr.keysym == GK_Escape )
     627           0 : return( false );
     628             : 
     629           0 :     GDrawCancelTimer(gl->enduser); gl->enduser = NULL; gl->sofar_pos = 0;
     630             : 
     631           0 :     loff = 0x80000000; xoff = 0x80000000; sel = -1;
     632           0 :     if ( keysym == GK_Home || keysym == GK_KP_Home || keysym == GK_Begin || keysym == GK_KP_Begin ) {
     633           0 :         loff = -gl->loff;
     634           0 :         xoff = -gl->xoff;
     635           0 :         sel = 0;
     636           0 :     } else if ( keysym == GK_End || keysym == GK_KP_End ) {
     637           0 :         loff = GListTopInWindow(gl,gl->ltot-1)-gl->loff;
     638           0 :         xoff = -gl->xoff;
     639           0 :         sel = gl->ltot-1;
     640           0 :     } else if ( keysym == GK_Up || keysym == GK_KP_Up ) {
     641           0 :         if (( sel = GListGetFirstSelPos(&gl->g)-1 )<0 ) {
     642             :             /*if ( gl->loff!=0 ) loff = -1; else loff = 0;*/
     643           0 :             sel = 0;
     644             :         }
     645           0 :     } else if ( keysym == GK_Down || keysym == GK_KP_Down ) {
     646           0 :         if (( sel = GListGetFirstSelPos(&gl->g))!= -1 )
     647           0 :             ++sel;
     648             :         else
     649             :             /*if ( gl->loff + GListLinesInWindow(gl,gl->loff)<gl->ltot ) loff = 1; else loff = 0;*/
     650           0 :             sel = 0;
     651           0 :     } else if ( keysym == GK_Left || keysym == GK_KP_Left ) {
     652           0 :         xoff = -GDrawPointsToPixels(gl->g.base,6);
     653           0 :     } else if ( keysym == GK_Right || keysym == GK_KP_Right ) {
     654           0 :         xoff = GDrawPointsToPixels(gl->g.base,6);
     655           0 :     } else if ( keysym == GK_Page_Up || keysym == GK_KP_Page_Up ) {
     656           0 :         loff = GListTopInWindow(gl,gl->loff);
     657           0 :         if ( loff == gl->loff )              /* Normally we leave one line in window from before, except if only one line fits */
     658           0 :             loff = GListTopInWindow(gl,gl->loff-1);
     659           0 :         loff -= gl->loff;
     660           0 :         if (( sel = GListGetFirstSelPos(&gl->g))!= -1 ) {
     661           0 :             if (( sel += loff )<0 ) sel = 0;
     662             :         }
     663           0 :     } else if ( keysym == GK_Page_Down || keysym == GK_KP_Page_Down ) {
     664           0 :         loff = GListLinesInWindow(gl,gl->loff)-1;
     665           0 :         if ( loff<=0 ) loff = 1;
     666           0 :         if ( loff + gl->loff >= gl->ltot )
     667           0 :             loff = GListTopInWindow(gl,gl->ltot-1)-gl->loff;
     668           0 :         if (( sel = GListGetFirstSelPos(&gl->g))!= -1 ) {
     669           0 :             if (( sel += loff )>=gl->ltot ) sel = gl->ltot-1;
     670             :         }
     671           0 :     } else if ( keysym == GK_BackSpace && gl->orderer ) {
     672             :         /* ordered lists may be reversed by typing backspace */
     673           0 :         gl->backwards = !gl->backwards;
     674           0 :         GListOrderIt(gl);
     675           0 :         sel = GListGetFirstSelPos(&gl->g);
     676           0 :         if ( sel!=-1 ) {
     677           0 :             int top = GListTopInWindow(gl,gl->ltot-1);
     678           0 :             gl->loff = sel-1;
     679           0 :             if ( gl->loff > top )
     680           0 :                 gl->loff = top;
     681           0 :             if ( sel-1<0 )
     682           0 :                 gl->loff = 0;
     683             :         }
     684           0 :         GScrollBarSetPos(&gl->vsb->g,gl->loff);
     685           0 :         _ggadget_redraw(&gl->g);
     686           0 : return( true );
     687           0 :     } else if ( event->u.chr.chars[0]!='\0' && gl->orderer ) {
     688           0 :         int len = u_strlen(event->u.chr.chars);
     689           0 :         if ( sofar_pos+len >= gl->sofar_max ) {
     690           0 :             if ( gl->sofar_max == 0 )
     691           0 :                 gl->sofar = malloc((gl->sofar_max = len+10) * sizeof(unichar_t));
     692             :             else
     693           0 :                 gl->sofar = realloc(gl->sofar,(gl->sofar_max = sofar_pos+len+10)*sizeof(unichar_t));
     694             :         }
     695           0 :         u_strcpy(gl->sofar+sofar_pos,event->u.chr.chars);
     696           0 :         gl->sofar_pos = sofar_pos + len;
     697           0 :         sel = GListFindPosition(gl,gl->sofar);
     698           0 :         gl->enduser = GDrawRequestTimer(gl->g.base,GListTypeTime,0,NULL);
     699             :     }
     700             : 
     701           0 :     if ( loff==0x80000000 && sel>=0 ) {
     702           0 :         if ( sel>=gl->ltot ) sel = gl->ltot-1;
     703           0 :         if ( sel<gl->loff ) loff = sel-gl->loff;
     704           0 :         else if ( sel>=gl->loff+GListLinesInWindow(gl,gl->loff) )
     705           0 :             loff = sel-(gl->loff+GListLinesInWindow(gl,gl->loff)-1);
     706             :     } else
     707           0 :         sel = -1;
     708           0 :     if ( sel!=-1 ) {
     709           0 :         int wassel = gl->ti[sel]->selected;
     710           0 :         refresh = GListAnyOtherSels(gl,sel) || !wassel;
     711           0 :         GListSelectOne(&gl->g,sel);
     712           0 :         if ( refresh )
     713           0 :             GListSelected(gl,false,sel);
     714             :     }
     715           0 :     if ( loff!=0x80000000 || xoff!=0x80000000 ) {
     716           0 :         if ( loff==0x80000000 ) loff = 0;
     717           0 :         if ( xoff==0x80000000 ) xoff = 0;
     718           0 :         GListScrollBy(gl,loff,xoff);
     719             :     }
     720           0 :     if ( refresh )
     721           0 :         _ggadget_redraw(g);
     722           0 :     if ( loff!=0x80000000 || xoff!=0x80000000 || sel!=-1 )
     723           0 : return( true );
     724             : 
     725           0 : return( false );
     726             : }
     727             : 
     728           0 : static int glist_timer(GGadget *g, GEvent *event) {
     729           0 :     GList *gl = (GList *) g;
     730             : 
     731           0 :     if ( event->u.timer.timer == gl->enduser ) {
     732           0 :         gl->enduser = NULL;
     733           0 :         gl->sofar_pos = 0;
     734           0 : return( true );
     735           0 :     } else if ( event->u.timer.timer == gl->pressed ) {
     736             :         GEvent e;
     737           0 :         e.type = et_mousemove;
     738           0 :         GDrawGetPointerPosition(g->base,&e);
     739           0 :         if ( e.u.mouse.x<g->inner.x || e.u.mouse.y <g->inner.y ||
     740           0 :                 e.u.mouse.x >= g->inner.x + g->inner.width ||
     741           0 :                 e.u.mouse.y >= g->inner.y + g->inner.height )
     742           0 :             glist_scroll_selbymouse(gl,&e);
     743           0 : return( true );
     744             :     }
     745           0 : return( false );
     746             : }
     747             : 
     748           0 : static int glist_scroll(GGadget *g, GEvent *event) {
     749           0 :     int loff = 0;
     750           0 :     enum sb sbt = event->u.control.u.sb.type;
     751           0 :     GList *gl = (GList *) (g->data);
     752             : 
     753           0 :     g = (GGadget *) gl;
     754             : 
     755           0 :     if ( sbt==et_sb_top )
     756           0 :         loff = -gl->loff;
     757           0 :     else if ( sbt==et_sb_bottom )
     758           0 :         loff = GListTopInWindow(gl,gl->ltot-1)-gl->loff;
     759           0 :     else if ( sbt==et_sb_up ) {
     760           0 :         if ( gl->loff!=0 ) loff = -1; else loff = 0;
     761           0 :     } else if ( sbt==et_sb_down ) {
     762           0 :         if ( gl->loff + GListLinesInWindow(gl,gl->loff)<gl->ltot ) loff = 1; else loff = 0;
     763           0 :     } else if ( sbt==et_sb_uppage ) {
     764           0 :         loff = GListTopInWindow(gl,gl->loff);
     765           0 :         if ( loff == gl->loff )              /* Normally we leave one line in window from before, except if only one line fits */
     766           0 :             loff = GListTopInWindow(gl,gl->loff-1);
     767           0 :         loff -= gl->loff;
     768           0 :     } else if ( sbt==et_sb_downpage ) {
     769           0 :         loff = GListLinesInWindow(gl,gl->loff)-1;
     770           0 :         if ( loff<=0 ) loff = 1;
     771           0 :         if ( loff + gl->loff >= gl->ltot )
     772           0 :             loff = GListTopInWindow(gl,gl->ltot-1)-gl->loff;
     773             :     } else /* if ( sbt==et_sb_thumb || sbt==et_sb_thumbrelease ) */ {
     774           0 :         loff = event->u.control.u.sb.pos - gl->loff;
     775             :     }
     776           0 :     GListScrollBy(gl,loff,0);
     777           0 : return( true );
     778             : }
     779             : 
     780           0 : static void GList_destroy(GGadget *g) {
     781           0 :     GList *gl = (GList *) g;
     782             : 
     783           0 :     if ( gl==NULL )
     784           0 : return;
     785           0 :     GDrawCancelTimer(gl->enduser);
     786           0 :     GDrawCancelTimer(gl->pressed);
     787           0 :     if ( gl->freeti )
     788           0 :         GTextInfoArrayFree(gl->ti);
     789           0 :     free(gl->sofar);
     790           0 :     if ( gl->vsb!=NULL )
     791           0 :         (gl->vsb->g.funcs->destroy)(&gl->vsb->g);
     792           0 :     _ggadget_destroy(g);
     793             : }
     794             : 
     795           0 : static void GListSetFont(GGadget *g,FontInstance *new) {
     796           0 :     GList *gl = (GList *) g;
     797             :     int same;
     798             : 
     799           0 :     gl->font = new;
     800           0 :     gl->hmax = GTextInfoGetMaxHeight(gl->g.base,gl->ti,gl->font,&same);
     801           0 :     gl->sameheight = same;
     802           0 : }
     803             : 
     804           0 : static FontInstance *GListGetFont(GGadget *g) {
     805           0 :     GList *b = (GList *) g;
     806           0 : return( b->font );
     807             : }
     808             : 
     809           0 : static void glist_redraw(GGadget *g) {
     810           0 :     GList *gl = (GList *) g;
     811           0 :     if ( gl->vsb!=NULL )
     812           0 :         _ggadget_redraw((GGadget *) (gl->vsb));
     813           0 :     _ggadget_redraw(g);
     814           0 : }
     815             : 
     816           0 : static void glist_move(GGadget *g, int32 x, int32 y ) {
     817           0 :     GList *gl = (GList *) g;
     818           0 :     if ( gl->vsb!=NULL )
     819           0 :         _ggadget_move((GGadget *) (gl->vsb),x+(gl->vsb->g.r.x-g->r.x),y);
     820           0 :     _ggadget_move(g,x,y);
     821           0 : }
     822             : 
     823           0 : static void glist_resize(GGadget *g, int32 width, int32 height ) {
     824           0 :     GList *gl = (GList *) g;
     825           0 :     if ( gl->vsb!=NULL ) {
     826           0 :         int oldwidth = gl->vsb->g.r.x+gl->vsb->g.r.width-g->r.x;
     827           0 :         _ggadget_move((GGadget *) (gl->vsb),gl->vsb->g.r.x+width-oldwidth,gl->vsb->g.r.y);
     828           0 :         _ggadget_resize(g,width-(oldwidth-g->r.width), height);
     829           0 :         _ggadget_resize((GGadget *) (gl->vsb),gl->vsb->g.r.width,height);
     830           0 :         GListCheckSB(gl);
     831             :     } else
     832           0 :         _ggadget_resize(g,width,height);
     833           0 : }
     834             : 
     835           0 : static GRect *glist_getsize(GGadget *g, GRect *r ) {
     836           0 :     GList *gl = (GList *) g;
     837           0 :     _ggadget_getsize(g,r);
     838           0 :     if ( gl->vsb!=NULL )
     839           0 :         r->width =  gl->vsb->g.r.x+gl->vsb->g.r.width-g->r.x;
     840           0 : return( r );
     841             : }
     842             : 
     843           0 : static void glist_setvisible(GGadget *g, int visible ) {
     844           0 :     GList *gl = (GList *) g;
     845           0 :     if ( gl->vsb!=NULL ) _ggadget_setvisible(&gl->vsb->g,visible);
     846           0 :     _ggadget_setvisible(g,visible);
     847           0 : }
     848             : 
     849           0 : static void glist_setenabled(GGadget *g, int enabled ) {
     850           0 :     GList *gl = (GList *) g;
     851           0 :     if ( gl->vsb!=NULL ) _ggadget_setenabled(&gl->vsb->g,enabled);
     852           0 :     _ggadget_setenabled(g,enabled);
     853           0 : }
     854             : 
     855           0 : static void GListGetDesiredSize(GGadget *g,GRect *outer, GRect *inner) {
     856           0 :     GList *gl = (GList *) g;
     857           0 :     int width=0, height=0, temp;
     858           0 :     int bp = GBoxBorderWidth(gl->g.base,gl->g.box);
     859             :     int i;
     860             : 
     861             :     /* can't deal with eliptical scrolling lists nor diamond ones. Just rects and roundrects */
     862           0 :     if ( g->desired_width<=0 ) {
     863           0 :         GListFindXMax(gl);
     864             : 
     865           0 :         width = gl->xmax;
     866           0 :         temp = GDrawPointsToPixels(gl->g.base,50);
     867           0 :         if ( width<temp ) width = temp;
     868           0 :         width += GDrawPointsToPixels(gl->g.base,_GScrollBar_Width) +
     869           0 :                 GDrawPointsToPixels(gl->g.base,1);
     870             :     } else
     871           0 :         width = g->desired_width - 2*bp;
     872             : 
     873           0 :     if ( g->desired_height<=0 ) {
     874           0 :         for ( i=0; i<gl->ltot && i<8; ++i ) {
     875           0 :             height += GTextInfoGetHeight(gl->g.base,gl->ti[i],gl->font);
     876             :         }
     877           0 :         if ( i<4 ) {
     878             :             int as, ds, ld;
     879           0 :             GDrawWindowFontMetrics(g->base,gl->font,&as, &ds, &ld);
     880           0 :             height += (4-i)*(as+ds);
     881             :         }
     882             :     } else
     883           0 :         height = g->desired_height - 2*bp;
     884           0 :     if ( inner!=NULL ) {
     885           0 :         inner->x = inner->y = 0;
     886           0 :         inner->width = width;
     887           0 :         inner->height = height;
     888             :     }
     889           0 :     if ( outer!=NULL ) {
     890           0 :         outer->x = outer->y = 0;
     891           0 :         outer->width = width + 2*bp;
     892           0 :         outer->height = height + 2*bp;
     893             :     }
     894           0 : }
     895             : 
     896           0 : static int glist_FillsWindow(GGadget *g) {
     897           0 : return( g->prev==NULL &&
     898           0 :         (_GWidgetGetGadgets(g->base)==g ||
     899           0 :          _GWidgetGetGadgets(g->base)==(GGadget *) ((GList *) g)->vsb));
     900             : }
     901             : 
     902             : struct gfuncs GList_funcs = {
     903             :     0,
     904             :     sizeof(struct gfuncs),
     905             : 
     906             :     glist_expose,
     907             :     glist_mouse,
     908             :     glist_key,
     909             :     NULL,
     910             :     NULL,
     911             :     glist_timer,
     912             :     NULL,
     913             : 
     914             :     glist_redraw,
     915             :     glist_move,
     916             :     glist_resize,
     917             :     glist_setvisible,
     918             :     glist_setenabled,
     919             :     glist_getsize,
     920             :     _ggadget_getinnersize,
     921             : 
     922             :     GList_destroy,
     923             : 
     924             :     NULL,
     925             :     NULL,
     926             :     NULL,
     927             :     NULL,
     928             :     NULL,
     929             :     GListSetFont,
     930             :     GListGetFont,
     931             : 
     932             :     GListClear,
     933             :     GListSetList,
     934             :     GListGetList,
     935             :     GListGetListItem,
     936             :     GListSelect,
     937             :     GListSelectOne,
     938             :     GListIsItemSelected,
     939             :     GListGetFirstSelPos,
     940             :     GListShowPos,
     941             :     GListScrollToText,
     942             :     GListSetOrderer,
     943             : 
     944             :     GListGetDesiredSize,
     945             :     _ggadget_setDesiredSize,
     946             :     glist_FillsWindow,
     947             :     NULL
     948             : };
     949             : 
     950             : static GBox list_box = GBOX_EMPTY; /* Don't initialize here */;
     951             : static FontInstance *list_font = NULL;
     952             : static int glist_inited = false;
     953             : 
     954             : static GTextInfo list_choices[] = {
     955             :     { (unichar_t *) "1", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     956             :     { (unichar_t *) "2", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     957             :     { (unichar_t *) "3", NULL, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 1, 0, 0, '\0' },
     958             :     GTEXTINFO_EMPTY
     959             : };
     960             : static GGadgetCreateData list_gcd[] = {
     961             :     { GListCreate, { { 0, 0, 0, 36 }, NULL, 0, 0, 0, 0, 0, &list_choices[0], { list_choices }, gg_visible, NULL, NULL }, NULL, NULL },
     962             :     { GListCreate, { { 0, 0, 0, 36 }, NULL, 0, 0, 0, 0, 0, &list_choices[0], { list_choices }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL }
     963             : };
     964             : static GGadgetCreateData *tarray[] = { GCD_Glue, &list_gcd[0], GCD_Glue, &list_gcd[1], GCD_Glue, NULL, NULL };
     965             : static GGadgetCreateData listhvbox =
     966             :     { GHVGroupCreate, { { 2, 2, 0, 0 }, NULL, 0, 0, 0, 0, 0, NULL, { (GTextInfo *) tarray }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL };
     967             : static GResInfo glist_ri = {
     968             :     NULL, &ggadget_ri,NULL, NULL,
     969             :     &list_box,
     970             :     &list_font,
     971             :     &listhvbox,
     972             :     NULL,
     973             :     N_("List"),
     974             :     N_("List"),
     975             :     "GList",
     976             :     "Gdraw",
     977             :     false,
     978             :     box_foreground_border_outer,
     979             :     NULL,
     980             :     GBOX_EMPTY,
     981             :     NULL,
     982             :     NULL,
     983             :     NULL
     984             : };
     985             : 
     986           0 : static void GListInit() {
     987           0 :     _GGadgetCopyDefaultBox(&list_box);
     988           0 :     list_box.flags |= box_foreground_border_outer;
     989           0 :     list_font = _GGadgetInitDefaultBox("GList.",&list_box,NULL);
     990           0 :     glist_inited = true;
     991           0 : }
     992             : 
     993           0 : static void GListFit(GList *gl) {
     994           0 :     int bp = GBoxBorderWidth(gl->g.base,gl->g.box);
     995             :     GRect inner, outer;
     996             : 
     997           0 :     GListGetDesiredSize(&gl->g,&outer,&inner);
     998           0 :     if ( gl->g.r.width==0 )
     999           0 :         gl->g.r.width = outer.width;
    1000           0 :     if ( gl->g.r.height==0 )
    1001           0 :         gl->g.r.height = outer.height;
    1002           0 :     gl->g.inner = gl->g.r;
    1003           0 :     gl->g.inner.x += bp; gl->g.inner.y += bp;
    1004           0 :     gl->g.inner.width -= 2*bp; gl->g.inner.height -= 2*bp;
    1005           0 :     GListCheckSB(gl);
    1006           0 : }
    1007             : 
    1008           0 : static GList *_GListCreate(GList *gl, struct gwindow *base, GGadgetData *gd,void *data, GBox *def) {
    1009             :     int same;
    1010             : 
    1011           0 :     if ( !glist_inited )
    1012           0 :         GListInit();
    1013           0 :     gl->g.funcs = &GList_funcs;
    1014           0 :     _GGadget_Create(&gl->g,base,gd,data,def);
    1015           0 :     gl->font = list_font;
    1016           0 :     gl->g.takes_input = gl->g.takes_keyboard = true; gl->g.focusable = true;
    1017             : 
    1018           0 :     if ( !(gd->flags & gg_list_internal ) ) {
    1019           0 :         gl->ti = GTextInfoArrayFromList(gd->u.list,&gl->ltot);
    1020           0 :         gl->freeti = true;
    1021             :     } else {
    1022           0 :         gl->ti = (GTextInfo **) (gd->u.list);
    1023           0 :         gl->ltot = GTextInfoArrayCount(gl->ti);
    1024             :     }
    1025           0 :     gl->hmax = GTextInfoGetMaxHeight(gl->g.base,gl->ti,gl->font,&same);
    1026           0 :     gl->sameheight = same;
    1027           0 :     if ( gd->flags & gg_list_alphabetic ) {
    1028           0 :         gl->orderer = GListAlphaCompare;
    1029           0 :         GListOrderIt(gl);
    1030             :     }
    1031           0 :     gl->start = gl->end = -1;
    1032           0 :     if ( gd->flags & gg_list_multiplesel )
    1033           0 :         gl->multiple_sel = true;
    1034           0 :     else if ( gd->flags & gg_list_exactlyone ) {
    1035           0 :         int sel = GListGetFirstSelPos(&gl->g);
    1036           0 :         gl->exactly_one = true;
    1037           0 :         if ( sel==-1 ) sel = 0;
    1038           0 :         GListClearSel(gl);
    1039           0 :         if ( gl->ltot>0 ) gl->ti[sel]->selected = true;
    1040             :     }
    1041             : 
    1042           0 :     GListFit(gl);
    1043           0 :     _GGadget_FinalPosition(&gl->g,base,gd);
    1044             : 
    1045           0 :     if ( gd->flags & gg_group_end )
    1046           0 :         _GGadgetCloseGroup(&gl->g);
    1047           0 :     GWidgetIndicateFocusGadget(&gl->g);
    1048           0 : return( gl );
    1049             : }
    1050             : 
    1051           0 : GGadget *GListCreate(struct gwindow *base, GGadgetData *gd,void *data) {
    1052           0 :     GList *gl = _GListCreate(calloc(1,sizeof(GList)),base,gd,data,&list_box);
    1053             : 
    1054           0 : return( &gl->g );
    1055             : }
    1056             : 
    1057           0 : static int popup_eh(GWindow popup,GEvent *event) {
    1058           0 :     GGadget *owner = GDrawGetUserData(popup);
    1059             : 
    1060           0 :     if ( event->type == et_controlevent ) {
    1061           0 :         GList *gl = (GList *) (event->u.control.g);
    1062           0 :         void (*inform)(GGadget *,int) = (void (*) (GGadget *,int)) GGadgetGetUserData(&gl->g);
    1063             :         int i;
    1064           0 :         for ( i=0; i<gl->ltot; ++i )
    1065           0 :             if ( gl->ti[i]->selected )
    1066           0 :         break;
    1067           0 :         if ( i>=gl->ltot ) i = -1;
    1068           0 :         GDrawDestroyWindow(popup);
    1069           0 :         (inform)(owner,i);
    1070           0 :     } else if ( event->type == et_close ) {
    1071           0 :         GGadget *g = GWindowGetFocusGadgetOfWindow(popup);
    1072           0 :         void (*inform)(GGadget *,int) = (void (*) (GGadget *,int)) GGadgetGetUserData(g);
    1073           0 :         GDrawDestroyWindow(popup);
    1074           0 :         _GWidget_ClearPopupOwner(owner);
    1075           0 :         _GWidget_ClearGrabGadget(owner);
    1076           0 :         (inform)(owner,-1);
    1077           0 :     } else if ( event->type == et_destroy ) {
    1078           0 :         _GWidget_ClearPopupOwner(owner);
    1079           0 :         _GWidget_ClearGrabGadget(owner);
    1080             :     }
    1081           0 : return( true );
    1082             : }
    1083             :         
    1084           0 : static void GListPopupFigurePos(GGadget *owner,GTextInfo **ti,GRect *pos) {
    1085             :     int width, height, width1, maxh;
    1086             :     int i;
    1087           0 :     GWindow root = GDrawGetRoot(GDrawGetDisplayOfWindow(owner->base));
    1088             :     GRect rsize, rootsize;
    1089             :     int bp;
    1090             :     GPoint pt;
    1091             : 
    1092           0 :     if ( !glist_inited )
    1093           0 :         GListInit();
    1094           0 :     GDrawGetSize(GDrawGetRoot(GDrawGetDisplayOfWindow(owner->base)),&rootsize);
    1095           0 :     maxh = 2*rootsize.height/3;
    1096           0 :     width = GTextInfoGetMaxWidth(owner->base,ti,list_font);
    1097           0 :     height = 0;
    1098           0 :     for ( i=0; height<maxh && (ti[i]->text!=NULL || ti[i]->image!=NULL || ti[i]->line); ++i )
    1099           0 :         height += GTextInfoGetHeight(owner->base,ti[i],list_font);
    1100           0 :     if ( ti[i]->text!=NULL || ti[i]->image!=NULL || ti[i]->line )      /* Need a scroll bar if more */
    1101           0 :         width += GDrawPointsToPixels(owner->base,_GScrollBar_Width) +
    1102           0 :                 GDrawPointsToPixels(owner->base,1);
    1103           0 :     bp = GBoxBorderWidth(owner->base,&list_box);
    1104           0 :     width += 2*bp; height += 2*bp;
    1105           0 :     if ( (width1 = width)<owner->r.width ) width = owner->r.width;
    1106             : 
    1107           0 :     GDrawGetSize(root,&rsize);
    1108           0 :     if ( width>rsize.width ) width = rsize.width;
    1109           0 :     if ( height>rsize.height ) height = rsize.height;
    1110           0 :     pt.x = owner->r.x; pt.y = owner->r.y+owner->r.height;
    1111           0 :     GDrawTranslateCoordinates(owner->base,root,&pt);
    1112           0 :     if ( pt.y+height > rsize.height ) {
    1113           0 :         pt.x = owner->r.x; pt.y = owner->r.y-height;
    1114           0 :         GDrawTranslateCoordinates(owner->base,root,&pt);
    1115           0 :         if ( pt.y<0 ) {
    1116           0 :             pt.y = 0;
    1117             :             /* Ok, it will overlap the base widget. not that good an idea */
    1118           0 :             if ( pt.x+owner->r.width+width+3<rsize.width )
    1119           0 :                 pt.x += owner->r.width+3;
    1120           0 :             else if ( pt.x-width-3>=0 )
    1121           0 :                 pt.x -= width+3;
    1122             :             else {
    1123             :                 /* But there doesn't seem much we can do about it if we get here */
    1124             :                 ;
    1125             :             }
    1126             :         }
    1127             :     }
    1128           0 :     pos->y = pt.y;
    1129             : 
    1130           0 :     if ( pt.x+width > rsize.width ) width = width1;
    1131           0 :     if ( pt.x+width > rsize.width ) {
    1132           0 :         pt.x = owner->r.x+owner->r.width-width; pt.y = 0;
    1133           0 :         GDrawTranslateCoordinates(owner->base,root,&pt);
    1134           0 :         if ( pt.x<0 )
    1135           0 :             pt.x = 0;
    1136             :     }
    1137           0 :     pos->x = pt.x;
    1138           0 :     pos->width = width;
    1139           0 :     pos->height = height;
    1140           0 : }
    1141             : 
    1142           0 : GWindow GListPopupCreate(GGadget *owner,void (*inform)(GGadget *,int), GTextInfo **ti) {
    1143             :     GWindow popup;
    1144             :     GWindowAttrs pattrs;
    1145           0 :     GDisplay *disp = GDrawGetDisplayOfWindow(owner->base);
    1146             :     GRect pos;
    1147             :     GGadgetData gd;
    1148             :     GList *gl;
    1149             :     int i;
    1150             :     GEvent e;
    1151             : 
    1152           0 :     if ( ti==NULL )
    1153           0 : return(NULL);
    1154             : 
    1155           0 :     GDrawPointerUngrab(disp);
    1156           0 :     GDrawGetPointerPosition(owner->base,&e);
    1157             : 
    1158           0 :     pattrs.mask = wam_events|wam_nodecor|wam_positioned|wam_cursor|wam_transient|wam_verytransient;
    1159           0 :     pattrs.event_masks = -1;
    1160           0 :     pattrs.nodecoration = true;
    1161           0 :     pattrs.positioned = true;
    1162           0 :     pattrs.cursor = ct_pointer;
    1163           0 :     pattrs.transient = GWidgetGetTopWidget(owner->base);
    1164             : 
    1165           0 :     GListPopupFigurePos(owner,ti,&pos);
    1166           0 :     popup = GDrawCreateTopWindow(disp,&pos,popup_eh,owner,&pattrs);
    1167             : 
    1168           0 :     memset(&gd,'\0',sizeof(gd));
    1169           0 :     gd.pos.x = gd.pos.y = 0;
    1170           0 :     gd.pos.width = pos.width; gd.pos.height = pos.height;
    1171           0 :     gd.u.list = (GTextInfo *) ti;
    1172           0 :     gd.flags = gg_visible | gg_enabled | gg_pos_in_pixels | gg_list_internal |
    1173             :             gg_pos_use0;
    1174           0 :     gl = (GList *) GListCreate(popup,&gd,(void *) inform);
    1175           0 :     for ( i=0; ti[i]->text!=NULL || ti[i]->image!=NULL || ti[i]->line ; ++i )
    1176           0 :         if ( ti[i]->selected ) {
    1177           0 :             GListScrollBy(gl,i,0);
    1178           0 :     break;
    1179             :         }
    1180           0 :     GDrawSetVisible(popup,true);
    1181           0 :     GDrawPointerGrab(popup);
    1182           0 :     _GWidget_SetGrabGadget(&gl->g);
    1183           0 :     if ( e.u.mouse.state&(ksm_button1|ksm_button2|ksm_button3) )
    1184           0 :         gl->parentpressed = true;
    1185           0 :     gl->ispopup = true;
    1186           0 :     _GWidget_SetPopupOwner(owner);
    1187           0 : return( popup );
    1188             : }
    1189             : 
    1190           0 : int GListIndexFromY(GGadget *g,int y) {
    1191           0 : return( GListIndexFromPos( (GList *) g, y ));
    1192             : }
    1193             : 
    1194           0 : void GListSetSBAlwaysVisible(GGadget *g,int always) {
    1195           0 :     ((GList *) g)->always_show_sb = always;
    1196           0 : }
    1197             : 
    1198           0 : void GListSetPopupCallback(GGadget *g,void (*callback)(GGadget *,int)) {
    1199           0 :     ((GList *) g)->popup_callback = callback;
    1200           0 : }
    1201             : 
    1202           0 : GResInfo *_GListRIHead(void) {
    1203             :     int as,ds,ld;
    1204             : 
    1205           0 :     if ( !glist_inited )
    1206           0 :         GListInit();
    1207             :     /* bp = GBoxBorderWidth(GDrawGetRoot(NULL),&list_box);*/        /* This gives bizarre values */
    1208           0 :     GDrawWindowFontMetrics(GDrawGetRoot(NULL),list_font,&as, &ds, &ld);     /* I don't have a window yet... */
    1209           0 :     list_gcd[0].gd.pos.height = list_gcd[1].gd.pos.height = 2*(as+ds)+4;
    1210           0 : return( &glist_ri );
    1211             : }

Generated by: LCOV version 1.10