From 9404d2ea544b12b8b5ec43f67a934c2b22d77e4c Mon Sep 17 00:00:00 2001 From: Alessandro Bonazzi Date: Mon, 9 Jun 2025 01:21:21 +0200 Subject: [PATCH] Patch level : 01.00 0282 Files correlati : f23.dir f23.trr f9.dir f9.trr Bug : Aggiornamento FePA --- build/agalib01.sln | 117 + src/ba/recdesc/f23.dir | 2 +- src/ba/recdesc/f23.trr | 5 +- src/ba/recdesc/f9.dir | 2 +- src/ba/recdesc/f9.trr | 6 +- src/xi01/xi.c | 4442 ++++++++++++++++++++++++++++++ src/xi01/xi.h | 1534 +++++++++++ src/xi01/xi2.c | 4014 +++++++++++++++++++++++++++ src/xi01/xi_int.h | 40 + src/xi01/xibitmap.c | 284 ++ src/xi01/xicf.c | 1344 +++++++++ src/xi01/xidbg.c | 478 ++++ src/xi01/xidisply.h | 34 + src/xi01/xierr.c | 316 +++ src/xi01/xiextend.h | 65 + src/xi01/xiheap.c | 59 + src/xi01/xiheap.h | 49 + src/xi01/xil.h | 48 + src/xi01/xilm.c | 1622 +++++++++++ src/xi01/xilm.h | 679 +++++ src/xi01/xilm2.c | 5291 +++++++++++++++++++++++++++++++++++ src/xi01/xilm3.c | 4899 +++++++++++++++++++++++++++++++++ src/xi01/xilmst.c | 915 +++++++ src/xi01/xilmst.h | 96 + src/xi01/xiport.c | 5911 ++++++++++++++++++++++++++++++++++++++++ src/xi01/xiport.h | 871 ++++++ src/xi01/xiport2.h | 17 + src/xi01/xires.h | 105 + src/xi01/xisetup.c | 20 + src/xi01/xistx.c | 1698 ++++++++++++ src/xi01/xistx.h | 157 ++ src/xi01/xitext.c | 3390 +++++++++++++++++++++++ src/xi01/xitext.h | 132 + src/xi01/xitree.c | 506 ++++ src/xi01/xiutils.c | 4160 ++++++++++++++++++++++++++++ src/xi01/xiutils.h | 133 + 36 files changed, 43437 insertions(+), 4 deletions(-) create mode 100644 build/agalib01.sln create mode 100644 src/xi01/xi.c create mode 100644 src/xi01/xi.h create mode 100644 src/xi01/xi2.c create mode 100644 src/xi01/xi_int.h create mode 100644 src/xi01/xibitmap.c create mode 100644 src/xi01/xicf.c create mode 100644 src/xi01/xidbg.c create mode 100644 src/xi01/xidisply.h create mode 100644 src/xi01/xierr.c create mode 100644 src/xi01/xiextend.h create mode 100644 src/xi01/xiheap.c create mode 100644 src/xi01/xiheap.h create mode 100644 src/xi01/xil.h create mode 100644 src/xi01/xilm.c create mode 100644 src/xi01/xilm.h create mode 100644 src/xi01/xilm2.c create mode 100644 src/xi01/xilm3.c create mode 100644 src/xi01/xilmst.c create mode 100644 src/xi01/xilmst.h create mode 100644 src/xi01/xiport.c create mode 100644 src/xi01/xiport.h create mode 100644 src/xi01/xiport2.h create mode 100644 src/xi01/xires.h create mode 100644 src/xi01/xisetup.c create mode 100644 src/xi01/xistx.c create mode 100644 src/xi01/xistx.h create mode 100644 src/xi01/xitext.c create mode 100644 src/xi01/xitext.h create mode 100644 src/xi01/xitree.c create mode 100644 src/xi01/xiutils.c create mode 100644 src/xi01/xiutils.h diff --git a/build/agalib01.sln b/build/agalib01.sln new file mode 100644 index 000000000..341548ca6 --- /dev/null +++ b/build/agalib01.sln @@ -0,0 +1,117 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2002 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AgaLib01", "AgaLib01.vcxproj", "{2D38A763-3D74-4338-9362-B891784EC90E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xi", "xi.vcxproj", "{3A5B0119-6DAD-4407-9EE1-3B739B0581E8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xvaga01", "xvaga01.vcxproj", "{4A2FC619-2461-4F58-8F1D-92FA153E39A2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xvapp", "xvapp.vcxproj", "{153C04B0-1F72-4DA9-8AC1-7DF76FFACFD2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xvtdb", "xvtdb.vcxproj", "{9C91BACF-9A70-4973-B8CC-FA3D2AF9867C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xvslt", "xvslt.vcxproj", "{7ECF3959-40CC-4BAA-A5E1-8699789AC386}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base64", "..\libraries\libb64\base64\VisualStudioProject\base64.vcxproj", "{0B094121-DC64-4D74-AFA0-750B83F800D0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfm", "gfm.vcxproj", "{37C3DDAE-3A63-4C1C-A419-242141B262ED}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Cb6", "Cb6.vcxproj", "{99683594-420F-4DD9-BB41-7DC48278B931}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pdflib", "pdflib_dll.vcxproj", "{A294C667-27A9-4125-82AF-5093447505EC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pdflibwrap", "pdflibwrap.vcxproj", "{21876C3B-F5A9-4AAA-9D58-F8DDDAF6F10C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Uno", "Uno.vcxproj", "{8B0477F1-5D74-46C3-97B6-8879E2460A71}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2D38A763-3D74-4338-9362-B891784EC90E}.Debug|Win32.ActiveCfg = Debug|Win32 + {2D38A763-3D74-4338-9362-B891784EC90E}.Debug|Win32.Build.0 = Debug|Win32 + {2D38A763-3D74-4338-9362-B891784EC90E}.Debug|x64.ActiveCfg = Debug|Win32 + {2D38A763-3D74-4338-9362-B891784EC90E}.Release|Win32.ActiveCfg = Release|Win32 + {2D38A763-3D74-4338-9362-B891784EC90E}.Release|Win32.Build.0 = Release|Win32 + {2D38A763-3D74-4338-9362-B891784EC90E}.Release|x64.ActiveCfg = Release|Win32 + {3A5B0119-6DAD-4407-9EE1-3B739B0581E8}.Debug|Win32.ActiveCfg = Debug|Win32 + {3A5B0119-6DAD-4407-9EE1-3B739B0581E8}.Debug|Win32.Build.0 = Debug|Win32 + {3A5B0119-6DAD-4407-9EE1-3B739B0581E8}.Debug|x64.ActiveCfg = Debug|Win32 + {3A5B0119-6DAD-4407-9EE1-3B739B0581E8}.Release|Win32.ActiveCfg = Release|Win32 + {3A5B0119-6DAD-4407-9EE1-3B739B0581E8}.Release|Win32.Build.0 = Release|Win32 + {3A5B0119-6DAD-4407-9EE1-3B739B0581E8}.Release|x64.ActiveCfg = Release|Win32 + {4A2FC619-2461-4F58-8F1D-92FA153E39A2}.Debug|Win32.ActiveCfg = Debug|Win32 + {4A2FC619-2461-4F58-8F1D-92FA153E39A2}.Debug|Win32.Build.0 = Debug|Win32 + {4A2FC619-2461-4F58-8F1D-92FA153E39A2}.Debug|x64.ActiveCfg = Debug|Win32 + {4A2FC619-2461-4F58-8F1D-92FA153E39A2}.Release|Win32.ActiveCfg = Release|Win32 + {4A2FC619-2461-4F58-8F1D-92FA153E39A2}.Release|Win32.Build.0 = Release|Win32 + {4A2FC619-2461-4F58-8F1D-92FA153E39A2}.Release|x64.ActiveCfg = Release|Win32 + {153C04B0-1F72-4DA9-8AC1-7DF76FFACFD2}.Debug|Win32.ActiveCfg = Debug|Win32 + {153C04B0-1F72-4DA9-8AC1-7DF76FFACFD2}.Debug|Win32.Build.0 = Debug|Win32 + {153C04B0-1F72-4DA9-8AC1-7DF76FFACFD2}.Debug|x64.ActiveCfg = Debug|Win32 + {153C04B0-1F72-4DA9-8AC1-7DF76FFACFD2}.Release|Win32.ActiveCfg = Release|Win32 + {153C04B0-1F72-4DA9-8AC1-7DF76FFACFD2}.Release|Win32.Build.0 = Release|Win32 + {153C04B0-1F72-4DA9-8AC1-7DF76FFACFD2}.Release|x64.ActiveCfg = Release|Win32 + {9C91BACF-9A70-4973-B8CC-FA3D2AF9867C}.Debug|Win32.ActiveCfg = Release|Win32 + {9C91BACF-9A70-4973-B8CC-FA3D2AF9867C}.Debug|Win32.Build.0 = Release|Win32 + {9C91BACF-9A70-4973-B8CC-FA3D2AF9867C}.Debug|x64.ActiveCfg = Debug|Win32 + {9C91BACF-9A70-4973-B8CC-FA3D2AF9867C}.Release|Win32.ActiveCfg = Release|Win32 + {9C91BACF-9A70-4973-B8CC-FA3D2AF9867C}.Release|Win32.Build.0 = Release|Win32 + {9C91BACF-9A70-4973-B8CC-FA3D2AF9867C}.Release|x64.ActiveCfg = Release|Win32 + {7ECF3959-40CC-4BAA-A5E1-8699789AC386}.Debug|Win32.ActiveCfg = Debug|Win32 + {7ECF3959-40CC-4BAA-A5E1-8699789AC386}.Debug|Win32.Build.0 = Debug|Win32 + {7ECF3959-40CC-4BAA-A5E1-8699789AC386}.Debug|x64.ActiveCfg = Debug|Win32 + {7ECF3959-40CC-4BAA-A5E1-8699789AC386}.Release|Win32.ActiveCfg = Release|Win32 + {7ECF3959-40CC-4BAA-A5E1-8699789AC386}.Release|Win32.Build.0 = Release|Win32 + {7ECF3959-40CC-4BAA-A5E1-8699789AC386}.Release|x64.ActiveCfg = Release|Win32 + {0B094121-DC64-4D74-AFA0-750B83F800D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {0B094121-DC64-4D74-AFA0-750B83F800D0}.Debug|Win32.Build.0 = Debug|Win32 + {0B094121-DC64-4D74-AFA0-750B83F800D0}.Debug|x64.ActiveCfg = Debug|Win32 + {0B094121-DC64-4D74-AFA0-750B83F800D0}.Release|Win32.ActiveCfg = Release|Win32 + {0B094121-DC64-4D74-AFA0-750B83F800D0}.Release|Win32.Build.0 = Release|Win32 + {0B094121-DC64-4D74-AFA0-750B83F800D0}.Release|x64.ActiveCfg = Release|Win32 + {37C3DDAE-3A63-4C1C-A419-242141B262ED}.Debug|Win32.ActiveCfg = Debug|Win32 + {37C3DDAE-3A63-4C1C-A419-242141B262ED}.Debug|Win32.Build.0 = Debug|Win32 + {37C3DDAE-3A63-4C1C-A419-242141B262ED}.Debug|x64.ActiveCfg = Debug|Win32 + {37C3DDAE-3A63-4C1C-A419-242141B262ED}.Release|Win32.ActiveCfg = Release|Win32 + {37C3DDAE-3A63-4C1C-A419-242141B262ED}.Release|Win32.Build.0 = Release|Win32 + {37C3DDAE-3A63-4C1C-A419-242141B262ED}.Release|x64.ActiveCfg = Release|Win32 + {99683594-420F-4DD9-BB41-7DC48278B931}.Debug|Win32.ActiveCfg = Debug|Win32 + {99683594-420F-4DD9-BB41-7DC48278B931}.Debug|Win32.Build.0 = Debug|Win32 + {99683594-420F-4DD9-BB41-7DC48278B931}.Debug|x64.ActiveCfg = Debug|Win32 + {99683594-420F-4DD9-BB41-7DC48278B931}.Release|Win32.ActiveCfg = Release|Win32 + {99683594-420F-4DD9-BB41-7DC48278B931}.Release|Win32.Build.0 = Release|Win32 + {99683594-420F-4DD9-BB41-7DC48278B931}.Release|x64.ActiveCfg = Release|Win32 + {A294C667-27A9-4125-82AF-5093447505EC}.Debug|Win32.ActiveCfg = Debug|Win32 + {A294C667-27A9-4125-82AF-5093447505EC}.Debug|Win32.Build.0 = Debug|Win32 + {A294C667-27A9-4125-82AF-5093447505EC}.Debug|x64.ActiveCfg = Debug|Win32 + {A294C667-27A9-4125-82AF-5093447505EC}.Release|Win32.ActiveCfg = Release|Win32 + {A294C667-27A9-4125-82AF-5093447505EC}.Release|Win32.Build.0 = Release|Win32 + {A294C667-27A9-4125-82AF-5093447505EC}.Release|x64.ActiveCfg = Release|Win32 + {21876C3B-F5A9-4AAA-9D58-F8DDDAF6F10C}.Debug|Win32.ActiveCfg = Debug|Win32 + {21876C3B-F5A9-4AAA-9D58-F8DDDAF6F10C}.Debug|Win32.Build.0 = Debug|Win32 + {21876C3B-F5A9-4AAA-9D58-F8DDDAF6F10C}.Debug|x64.ActiveCfg = Debug|Win32 + {21876C3B-F5A9-4AAA-9D58-F8DDDAF6F10C}.Release|Win32.ActiveCfg = Release|Win32 + {21876C3B-F5A9-4AAA-9D58-F8DDDAF6F10C}.Release|Win32.Build.0 = Release|Win32 + {21876C3B-F5A9-4AAA-9D58-F8DDDAF6F10C}.Release|x64.ActiveCfg = Release|Win32 + {8B0477F1-5D74-46C3-97B6-8879E2460A71}.Debug|Win32.ActiveCfg = Debug|Win32 + {8B0477F1-5D74-46C3-97B6-8879E2460A71}.Debug|Win32.Build.0 = Debug|Win32 + {8B0477F1-5D74-46C3-97B6-8879E2460A71}.Debug|x64.ActiveCfg = Debug|Win32 + {8B0477F1-5D74-46C3-97B6-8879E2460A71}.Release|Win32.ActiveCfg = Release|Win32 + {8B0477F1-5D74-46C3-97B6-8879E2460A71}.Release|Win32.Build.0 = Release|Win32 + {8B0477F1-5D74-46C3-97B6-8879E2460A71}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F6953F85-8BF0-45D8-BFAA-DA516BDDEAED} + EndGlobalSection +EndGlobal diff --git a/src/ba/recdesc/f23.dir b/src/ba/recdesc/f23.dir index cab86bd09..7c9b08b95 100644 --- a/src/ba/recdesc/f23.dir +++ b/src/ba/recdesc/f23.dir @@ -1,3 +1,3 @@ 23 0 -$mov|0|0|714|0|Movimenti di prima nota||| +$mov|0|0|747|0|Movimenti di prima nota||| diff --git a/src/ba/recdesc/f23.trr b/src/ba/recdesc/f23.trr index 6ed7b0d86..34f011bae 100644 --- a/src/ba/recdesc/f23.trr +++ b/src/ba/recdesc/f23.trr @@ -1,5 +1,5 @@ 23 -68 +71 ANNOES|9|4|0|Codice esercizio NUMREG|3|7|0|Numero di operazione DATAREG|5|8|0|Data operazione @@ -68,6 +68,9 @@ DATADOCSDI|5|8|0|Data documento SDI COLL_GOLEM|11|10|0|Documenti generici CARTACEI|11|10|0|Documenti cartacei KEYPAF|1|80|0|Chiavi del PAFW300 [KEYPRGINVIO;KEYHEADERFATT;KEYBODYFATT] +XMLNAME|1|25|0|Nome del flie XML +PRGINVIO|1|7|0|Prgressivo invio +STATOSDI|1|1|0|Stato SDI 4 NUMREG| DATAREG+NUMREG|X diff --git a/src/ba/recdesc/f9.dir b/src/ba/recdesc/f9.dir index bcd2f9b30..50af8cbb5 100644 --- a/src/ba/recdesc/f9.dir +++ b/src/ba/recdesc/f9.dir @@ -1,3 +1,3 @@ 9 1 -%nditte|0|0|758|0|Ditte||| +%nditte|0|0|765|0|Ditte||| diff --git a/src/ba/recdesc/f9.trr b/src/ba/recdesc/f9.trr index 320c5790a..b9bf1cfeb 100644 --- a/src/ba/recdesc/f9.trr +++ b/src/ba/recdesc/f9.trr @@ -1,5 +1,5 @@ 9 -65 +69 CODDITTA|3|5|0| TIPOA|1|1|0| CODANAGR|3|5|0| @@ -34,6 +34,7 @@ RAPPR|3|5|0| CARRAPP|2|1|0| DECCARINT|5|8|0| REGSTATSP|8|1|0| +TIPOF|1|1|0|Tipo anagrafico del firmatario FIRMAT|3|5|0| AZCONIUG|8|1|0| MESIREDD|2|2|0| @@ -64,6 +65,9 @@ OGGETTI|11|10|0|Collegamenti esterni CODEORI|1|15|0|Codice EORI Ditta PEC|1|80|0|PEC PADESTIN|1|7|0|Codice destinatario SDI +TITOLO|1|0|0|Titolo onorifico +TIPOEMITT|1|0|0|Tipo anagrafico del'emittente +EMITT|3|6|0|Codice dell'emittente REGFISC|1|4|0|Regime fiscale 4 CODDITTA| diff --git a/src/xi01/xi.c b/src/xi01/xi.c new file mode 100644 index 000000000..b652a2ddb --- /dev/null +++ b/src/xi01/xi.c @@ -0,0 +1,4442 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ +#define XI_INTERNAL +#define XI_R3_COMPAT +#include "xi.h" +#include "xitext.h" +#include "xistx.h" +#include "xilm.h" +#include "xilmst.h" +#include "xiutils.h" +#include "xi_int.h" + +#if XIWS == XIWS_XM +#include +#include +#include +#endif + +#define MAXPIX 6000 + +#define VRCT_TO_PRCT( rp ) \ + ( rp )->left -= cur_delta_x; \ + ( rp )->right -= cur_delta_x; \ + ( rp )->top -= cur_delta_y; \ + ( rp )->bottom -= cur_delta_y; + + +/* ERROR CODES 20000-20089 */ + +BOOLEAN xi_false = FALSE; +void xi_finish_interface_create( XinWindow win ); +extern XI_OBJ *xi_creating_itf; + +static int xi_send_event( XI_OBJ * xi_obj, XinEvent * ep, BOOLEAN do_subtree ); + +#ifndef NO_PRIMARY_SELECTION +#if XIWS == XIWS_XM + +static XI_OBJ *rp_xi_obj = NULL; + +static void +receive_primesel( Widget widget, XtPointer data, Atom * selection, + Atom * type, XtPointer value, unsigned long *length, int *format ) +{ + char *s; + XinWindow win; + char *p; + + /* printf("receive_primesel: ENTERED, widget %d, selection %d, type %d\n", + * widget, *selection, *type); */ + /* printf(" length %d, format %d\n", length, + * *format); */ + + /* check if request for primary selection was successful */ + if ( *selection != XA_PRIMARY || *type != XA_STRING || *format != 8 ) + { + /* printf("receive_primesel: get primary selection failed\n"); */ + return; + } + + /* allocate space and fill in text from selection value */ + s = XinMemoryAlloc( *length + 1 ); + /* Assertion for out of memory? */ + strncpy( s, ( char * ) value, *length ); + s[*length] = '\0'; + /* printf("receive_primesel: primary selection text = '%s'\n", s); */ + XtFree( ( char * ) value ); /* this must be freed with XtFree */ + + /* xvt_dm_post_note("Text from Primary selection is '%s'", s); */ + if ( rp_xi_obj ) + { + win = xi_get_window( rp_xi_obj ); + rp_xi_obj = NULL; + for ( p = s; *p != '\0'; ++p ) + { + XinEvent ev; + + MEMCLEAR( ev ); + ev.type = XinEventCharacter; + ev.v.character.ch = ( unsigned char ) *p; + xi_event( win, &ev ); + XinWindowPaintForce( win ); + } + } + XinMemoryFree( s ); +} + + +static void +get_primary_selection( XI_OBJ * itf, XinWindow win ) +{ + Widget widget; + + rp_xi_obj = itf; + + /* printf("get_primary_selection: ENTERED, win %d\n", win); */ + + /* request PRIMARY selection */ + if ( rp_xi_obj) { + widget = ( Widget ) XinWindowWidgetGet( win ); + XtGetSelectionValue( widget, XA_PRIMARY, XA_STRING, receive_primesel, NULL, + XtLastTimestampProcessed( XtDisplay( widget ) ) ); + } + + /* printf("get_primary_selection: returning\n"); */ +} + +#endif +#endif + +BOOLEAN +call_cb( XI_OBJ * itf, XI_EVENT * xiev ) +{ + XI_ITF_DATA *itf_data; + + itf_data = itf->v.itf; + itf_data->in_callback++; + XinCoalesceInvalidates( itf_data->xin_win, TRUE ); + + ( *itf_data->xi_eh ) ( ( struct _xi_obj * ) itf, xiev ); +#ifdef WINRUNNER + xir_record( itf, xiev ); +#endif + if ( xi_is_itf( itf ) ) + { + XinCoalesceInvalidates( itf_data->xin_win, FALSE ); + itf_data->in_callback--; + if ( itf_data->in_callback == 0 && itf_data->closing ) + { + itf_data->closing = FALSE; + xi_close_window_internal( itf ); + return FALSE; + } + } + return TRUE; +} + +static long +event_to_longchar( XinEvent * ep ) +{ + long c = ep->v.character.ch; + + if ( ep->v.character.control ) + c |= XI_MOD_CONTROL; + if ( ep->v.character.shift ) + c |= XI_MOD_SHIFT; + if ( ep->v.character.alt ) + c |= XI_MOD_ALT; + return ( c ); +} + +void +xi_column_set_pixel_width( XI_OBJ * column, int width ) +{ + int i; + XI_LIST_DATA *list; + LM_DATA *lm_data; + + list = column->parent->v.list; + lm_data = ( LM_DATA * ) list->lm; + if ( column->type != XIT_COLUMN ) + XinError( 20010, XinSeverityFatal, 0L ); + lm_column_set_pixel_width( list->lm, xi_obj_to_idx( column ), width ); + if ( list->sb_win && ( !list->width ) ) + xi_move_list_scroll_bar( column->parent ); + i = xi_obj_to_idx( column ); + if ( i < lm_data->fixed_columns && list->hsb_win ) + xi_move_list_hscroll_bar( column->parent ); +} + +void +xi_set_column_width( XI_OBJ * column, int width ) +{ + int width_in_chars; + + if ( xi_get_xil_pref( column->itf ) ) + width_in_chars = width; + else + width_in_chars = width / XI_FU_MULTIPLE; + + xi_column_set_pixel_width( column, width_in_chars + * ( ( LM_DATA * ) column->parent->v.list->lm ) + ->pix_char_width ); +} + +static XI_OBJ * +xi_get_default( XI_OBJ * obj ) +{ + XI_OBJ **objlist; + XI_OBJ *temp; + int n; + + temp = obj->itf->v.itf->focus_obj; + if ( temp != NULL && temp->type == XIT_BTN ) + return temp; + + if ( obj->type == XIT_BTN && obj->v.btn->dflt ) + return obj; + + switch ( obj->type ) + { + case XIT_GROUP: + case XIT_CELL: + case XIT_ROW: + return NULL; + default: + break; + } + + /* search in child list */ + objlist = xi_get_member_list( obj, &n ); + for ( ; n > 0; n--, objlist++ ) + { + /* call recursively for generality in future versions */ + if ( ( temp = xi_get_default( *objlist ) ) != NULL ) + return temp; + } + return NULL; +} + +static XI_OBJ * +xi_get_cancel( XI_OBJ * obj ) +{ + XI_OBJ **objlist; + XI_OBJ *temp; + int n; + + if ( obj->type == XIT_BTN && obj->v.btn->cancel ) + return obj; + + switch ( obj->type ) + { + case XIT_GROUP: + case XIT_CELL: + case XIT_ROW: + return NULL; + default: + break; + } + + /* search in child list */ + objlist = xi_get_member_list( obj, &n ); + for ( ; n > 0; n--, objlist++ ) + { + /* call recursively for generality in future versions */ + if ( ( temp = xi_get_cancel( *objlist ) ) != NULL ) + return temp; + } + return NULL; +} + +XI_OBJ * +xi_get_obj_from_mnemonic( XI_OBJ * obj, char ch ) +{ + XI_OBJ **objlist; + XI_OBJ *temp; + int n; + + if ( obj->type == XIT_BTN && toupper( obj->v.btn->mnemonic ) == toupper( ch ) ) + return obj; + if ( obj->type == XIT_FIELD && toupper( obj->v.field->mnemonic ) == toupper( ch ) ) + return obj; + + switch ( obj->type ) + { + case XIT_GROUP: + case XIT_CELL: + case XIT_ROW: + return NULL; + default: + break; + } + + /* search in child list */ + objlist = xi_get_member_list( obj, &n ); + for ( ; n > 0; n--, objlist++ ) + { + /* call recursively for generality in future versions */ + if ( ( temp = xi_get_obj_from_mnemonic( *objlist, ch ) ) != NULL ) + return temp; + } + return NULL; +} + +void +xi_hscroll_internal( XI_OBJ * xi_obj, int nbr_lines, int pos ) +{ + XI_OBJ *itf; + XI_OBJ *focus; + LM lm = xi_obj->v.list->lm; + + itf = xi_obj->parent; + focus = xi_get_focus( itf ); + if ( focus && focus->parent == xi_obj ) + { + if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + { + lm_hscroll( lm, nbr_lines, pos ); + } + else + { + if ( xi_move_focus( itf ) ) + lm_hscroll( lm, nbr_lines, pos ); + } + } + else + lm_hscroll( lm, nbr_lines, pos ); +} + +void +xi_hscroll( XI_OBJ * xi_obj, int nbr_lines ) +{ + xi_hscroll_internal( xi_obj, nbr_lines, 0 ); +} + +static void +control_event_hscroll( XI_OBJ * xi_obj, int nbr_lines, int pos ) +{ + XI_LIST_DATA *list_data; + XI_OBJ *other_list; + + list_data = xi_obj->v.list; + xi_hscroll_internal( xi_obj, nbr_lines, pos ); + if ( list_data->horz_sync_list && + !list_data->scrolling_in_progress ) + { + list_data->scrolling_in_progress = TRUE; + other_list = xi_get_obj( xi_obj->itf, list_data->horz_sync_list ); + if ( other_list ) + xi_hscroll_internal( other_list, nbr_lines, pos ); + list_data->scrolling_in_progress = FALSE; + } +} + +void +xi_control_event_scroll( XI_OBJ * xi_obj, int nbr_lines, int percent, + BOOLEAN same_cell ) +{ + XI_LIST_DATA *list_data; + XI_OBJ *other_list; + + list_data = xi_obj->v.list; + xi_scroll_internal( xi_obj, nbr_lines, percent, same_cell ); + if ( list_data->vert_sync_list && + !list_data->scrolling_in_progress ) + { + list_data->scrolling_in_progress = TRUE; + other_list = xi_get_obj( xi_obj->itf, + list_data->vert_sync_list ); + if ( other_list ) + xi_scroll_internal( other_list, nbr_lines, percent, same_cell ); + list_data->scrolling_in_progress = FALSE; + } +} + +static void +control_event( XI_OBJ * itf, XinWindow win, XinEvent * ep ) +{ + XI_ITF_DATA *itf_data; + XI_OBJ *xi_obj; + + itf_data = itf->v.itf; + win = itf_data->xin_win; + if ( ep->v.control.control_id == XI_MULTILINE_SCROLLBAR_CID ) + { + XI_TEXT *text; + + text = xi_text_focus_get( itf_data->xin_win ); + if ( text && xi_text_editing_is( text ) ) + xi_text_event( text, ep, FALSE, NULL ); + return; + } + if ( ( xi_obj = xi_get_obj( itf, ep->v.control.control_id ) ) != NULL ) + { + switch ( xi_obj->type ) + { + case XIT_FIELD: + { + XI_TEXT *text; + + text = stx_xi_text_get( xi_obj->v.field->stx ); + if ( text ) /* && xi_text_editing_is( text ) ) */ + xi_text_event( text, ep, FALSE, NULL ); + return; + } + case XIT_BTN: + { + XI_EVENT xiev; + + XinWindow front_win = XinWindowFocusGet( ); + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = xi_obj; + call_cb( itf, &xiev ); + + if ( xi_is_itf( itf ) && xi_is_window( win ) + && xi_get_focus( itf ) != xi_obj ) + { + + if ( win ) + XinWindowFrontSet( win ); + if ( front_win != win && front_win ) + XinWindowFrontSet( front_win ); + } + + break; + } + case XIT_LIST: + { + switch ( ep->v.control.ctrl_info.v.scroll.action ) + { + case XinScrollBarActionLineUp: + xi_control_event_scroll( xi_obj, -1, 0, TRUE ); + break; + case XinScrollBarActionLineDown: + xi_control_event_scroll( xi_obj, 1, 0, TRUE ); + break; + case XinScrollBarActionPageUp: + xi_control_event_scroll( xi_obj, XI_SCROLL_PGUP, 0, TRUE ); + break; + case XinScrollBarActionPageDown: + xi_control_event_scroll( xi_obj, XI_SCROLL_PGDOWN, 0, TRUE ); + break; + case XinScrollBarActionThumb: + case XinScrollBarActionThumbTrack: + if (ep->v.control.ctrl_info.v.scroll.action == XinScrollBarActionThumbTrack && + xi_obj->v.list->scroll_on_thumb_track != TRUE) + break; + { + int percent = ep->v.control.ctrl_info.v.scroll.position; + + if ( XinScrollBarProportionGet( ep->v.control.ctrl_info.win, + XinScrollBarTypeEither ) + percent == 100 ) + xi_control_event_scroll( xi_obj, XI_SCROLL_LAST, 0, TRUE ); + else + xi_control_event_scroll( xi_obj, XI_SCROLL_FIRST, percent, TRUE ); + break; + } + default: + break; + } + break; + } + default: + break; + } + } + if ( xi_is_itf( itf ) && + ( xi_obj = xi_get_obj( itf, ep->v.control.control_id - HSCROLL_CID_CONST ) ) != NULL ) + { + switch ( xi_obj->type ) + { + case XIT_LIST: + switch ( ep->v.control.ctrl_info.v.scroll.action ) + { + case XinScrollBarActionLineUp: + control_event_hscroll( xi_obj, -1, 0 ); + break; + case XinScrollBarActionLineDown: + control_event_hscroll( xi_obj, 1, 0 ); + break; + case XinScrollBarActionPageUp: + control_event_hscroll( xi_obj, XI_SCROLL_PGUP, 0 ); + break; + case XinScrollBarActionPageDown: + control_event_hscroll( xi_obj, XI_SCROLL_PGDOWN, 0 ); + break; + case XinScrollBarActionThumb: + case XinScrollBarActionThumbTrack: + if (ep->v.control.ctrl_info.v.scroll.action == XinScrollBarActionThumbTrack && + xi_obj->v.list->scroll_on_thumb_track != TRUE) + break; + { + int prop; + int rng1, + rng2; + int pos; + + prop = XinScrollBarProportionGet( ep->v.control.ctrl_info.win, + XinScrollBarTypeEither ); + XinScrollBarRangeGet( ep->v.control.ctrl_info.win, XinScrollBarTypeEither, + &rng1, &rng2 ); + pos = ( rng2 - rng1 - prop ) ? + ( int ) ( ep->v.control.ctrl_info.v.scroll.position * 100L / ( rng2 - rng1 - prop ) ) : 0; + control_event_hscroll( xi_obj, XI_SCROLL_FIRST, pos ); + break; + } + default: + break; + } + break; + default: + break; + } + } +} + +void +xi_set_trap_obj( XI_OBJ * xi_obj ) +{ + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + + itf = xi_obj->itf; + itf_data = itf->v.itf; + itf_data->trap_obj = xi_obj; + itf_data->trap_explicit = TRUE; +} + +static void +destroy_controls( XI_OBJ * xi_obj ) +{ + XI_OBJ **objp; + int i; + + switch ( xi_obj->type ) + { + case XIT_LIST: + if ( xi_obj->v.list->font ) + XinFontDestroy( xi_obj->v.list->font ); + lm_cleanup( xi_obj->v.list->lm ); + break; + case XIT_FIELD: + if ( xi_obj->v.field->font_set ) + stx_destroy_font( xi_obj->v.field->stx ); + break; + case XIT_TEXT: + if ( xi_obj->v.text->font ) + XinFontDestroy( xi_obj->v.text->font ); + break; + case XIT_ITF: + if ( xi_obj->v.itf->font ) + XinFontDestroy( xi_obj->v.itf->font ); + break; + case XIT_BTN: + xi_bitmap_destroy( xi_obj->v.btn->up_bitmap ); + xi_bitmap_destroy( xi_obj->v.btn->down_bitmap ); + xi_bitmap_destroy( xi_obj->v.btn->disabled_bitmap ); + break; + default: + break; + } + objp = xi_obj->children; + for ( i = xi_obj->nbr_children; i > 0; i--, objp++ ) + destroy_controls( *objp ); +} + +static void +copy_to_clip( XI_OBJ * focus_obj ) +{ + int b, + e; + char *buff; + + xi_get_sel( focus_obj, &b, &e ); + if ( b != e ) + { + long len; + + len = e - b; + buff = xi_get_text( focus_obj, NULL, 0 ); + XinClipboardPut( XinClipboardFormatText, len, &buff[b] ); + } +} + +static void +update_menus( void ) +{ + BOOLEAN paste_enable; + BOOLEAN cut_or_copy_enable = FALSE; + XI_OBJ *itf; + XI_ITF_DATA *itfdata; + XinWindow win; + + win = XinWindowFocusGet( ); + if ( win == XI_NULL_WINDOW || !xi_is_window( win ) ) + return; + itf = xi_get_itf( win ); + itfdata = itf->v.itf; + if ( itfdata->menu_win != XI_NULL_WINDOW ) + win = itfdata->menu_win; + if ( itfdata->edit_menu ) + { + XI_OBJ *focus_obj; + + paste_enable = XinClipboardFormatAvail( XinClipboardFormatText ); + XinWindowMenuItemEnable( win, XI_MENU_EDIT_PASTE, paste_enable ); + focus_obj = xi_get_focus( itf ); + if ( ( focus_obj && ( focus_obj->type == XIT_CELL ) ) || + ( focus_obj && ( focus_obj->type == XIT_FIELD ) ) ) + { + int s, + e; + + xi_get_sel( focus_obj, &s, &e ); + if ( s != e ) + cut_or_copy_enable = TRUE; + } + if ( paste_enable != itfdata->paste_enable ) + { + XinWindowMenuItemEnable( win, XI_MENU_EDIT_PASTE, paste_enable ); + itfdata->paste_enable = paste_enable; + } + if ( cut_or_copy_enable != itfdata->cut_or_copy_enable ) + { + XinWindowMenuItemEnable( win, XI_MENU_EDIT_CUT, cut_or_copy_enable ); + XinWindowMenuItemEnable( win, XI_MENU_EDIT_COPY, cut_or_copy_enable ); + XinWindowMenuItemEnable( win, XI_MENU_EDIT_CLEAR, cut_or_copy_enable ); + itfdata->cut_or_copy_enable = cut_or_copy_enable; + } + } +} + +static void +do_edit_menu( XI_OBJ * itf, XinEvent * ep ) +{ + XI_OBJ *focus_obj; + unsigned long attrib = 0L; + + focus_obj = xi_get_focus( itf ); + if ( focus_obj && focus_obj->type != XIT_ITF ) + { + switch ( focus_obj->type ) + { + case XIT_FIELD: + attrib = xi_get_attrib( focus_obj ); + break; + case XIT_CELL: + { + XI_OBJ *list; + XI_OBJ *column; + XI_OBJ **members; + int col_nbr, + nbr_members; + + list = focus_obj->parent; + members = xi_get_member_list( list, &nbr_members ); + col_nbr = focus_obj->v.cell.column; + column = members[col_nbr]; + attrib = xi_get_attrib( column ); + break; + } + default: + break; + } + if ( attrib & XI_ATR_EDITMENU ) + { + int b, e; + + switch ( ep->v.menu_command.tag ) + { + case XI_MENU_EDIT_CUT: + copy_to_clip( focus_obj ); + /* fall through */ + case XI_MENU_EDIT_CLEAR: + xi_get_sel( focus_obj, &b, &e ); +#if 1 // #ifdef XVAGA + if ( b == e ) + { + e++; + xi_set_sel( focus_obj, b, e ); + } +#endif + if ( b != e ) + { + XinEvent ev; + + MEMCLEAR( ev ); + ev.type = XinEventCharacter; + ev.v.character.ch = XI_KEY_DEL; + xi_event( xi_get_window( itf ), &ev ); + } + update_menus( ); + break; + case XI_MENU_EDIT_COPY: + copy_to_clip( focus_obj ); + update_menus( ); + break; + case XI_MENU_EDIT_PASTE: +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + if ( focus_obj->type == XIT_FIELD ) + if ( xi_is_txedit( focus_obj ) ) + if ( xi_get_pref( XI_PREF_MULTILINE_QUICK_PASTE ) ) + break; +#endif + { + char *cb, + *p; + long size; + + if ( ( cb = XinClipboardGet( XinClipboardFormatText, &size ) ) != NULL ) + { + XinWindow win; + + win = xi_get_window( itf ); + itf->v.itf->pasting = TRUE; + p = cb; + if ( ( focus_obj->type == XIT_FIELD || focus_obj->type == XIT_CELL ) && + xi_get_pref( XI_PREF_MULTILINE_QUICK_PASTE ) ) + { + XI_TEXT *text; + + text = xi_text_focus_get( win ); + if ( text ) + if ( text->multi_line ) + { + xi_text_paste_internal( text, p ); + itf->v.itf->pasting = FALSE; + XinMemoryFree( cb ); + + break; + } + } +/* Che programmatore cazzone! + while ( size-- > 0 ) + { + XinEvent ev; + + MEMCLEAR( ev ); + ev.type = XinEventCharacter; + ev.v.character.ch = ( unsigned char ) *p++; + xi_event( win, &ev ); + XinWindowPaintForce( win ); + } +*/ + if (size) // Molto meglio cosi! + { + XinEvent ev; + MEMCLEAR( ev ); + ev.type = XinEventCharacter; + while ( size-- > 0 ) + { + ev.v.character.ch = ( unsigned char ) *p++; + xi_event( win, &ev ); + } + } + + itf->v.itf->pasting = FALSE; + XinMemoryFree( cb ); + } + } + update_menus( ); + break; + } + } + } +} + +/* +count the number of children of xi_obj that have rectangles that will be completely +filled in when the child is drawn. +*/ +static int +count_children( XI_OBJ * xi_obj ) +{ + int idx; + int count = 0; + XI_OBJ **child; + + for ( idx = 0, child = xi_obj->children; idx < xi_obj->nbr_children; ++idx, ++child ) + { + XI_OBJ_TYPE type = ( *child )->type; + + if ( xi_get_attrib( *child ) & XI_ATR_VISIBLE ) + { + /* do not count groups, lines, static texts, or columns, nor their + * children */ + if ( type != XIT_GROUP && type != XIT_LINE && type != XIT_TEXT && type != XIT_COLUMN ) + { + /* count the children of containers, forms, and the interface, but not + * containers, forms, and interfaces */ + if ( ( *child )->type != XIT_LIST && ( *child )->children ) + count += count_children( *child ); + if ( type != XIT_CONTAINER && + type != XIT_FORM && + type != XIT_ITF && + type != XIT_TEXT && + type != XIT_BTN && + type != XIT_FIELD ) + ++count; + } + } + } + return count; +} + +static void +add_rects( XI_OBJ * xi_obj, XinRect * ra, int *ra_count ) +{ + int idx; + XI_OBJ **child; + + for ( idx = 0, child = xi_obj->children; idx < xi_obj->nbr_children; ++idx, ++child ) + { + XI_OBJ_TYPE type = ( *child )->type; + + if ( xi_get_attrib( *child ) & XI_ATR_VISIBLE ) + { + /* do not add rects for groups, lines, static texts, or columns, nor + * their children */ + if ( type != XIT_GROUP && type != XIT_LINE && type != XIT_TEXT && type != XIT_COLUMN ) + { + /* add rects for the children of containers, forms, and the interface, + * but not containers, forms, and interfaces */ + if ( ( *child )->type != XIT_LIST && ( *child )->children ) + add_rects( *child, ra, ra_count ); + if ( type != XIT_CONTAINER && + type != XIT_FORM && + type != XIT_ITF && + type != XIT_TEXT && + type != XIT_BTN && + type != XIT_FIELD ) + { + xi_get_rect( ( *child ), &ra[*ra_count] ); + ++*ra_count; + } + } + } + } +} + +#if XIWS == XIWS_PM +static int _Optlink +#else +static int +#endif +compare( const void *arg1, const void *arg2 ) +{ + if ( *( int * ) arg1 == *( int * ) arg2 ) + return 0; + if ( *( int * ) arg1 < *( int * ) arg2 ) + return -1; + return 1; +} + +static int +elim_dups( int *int_array, int int_count ) +{ + int index = 0; + int top = int_count - 1; + int *iap = int_array; + + while ( index < top ) + { + if ( *iap == *( iap + 1 ) ) + { + if ( top > index ) + memmove( iap + 1, iap + 2, ( top - index - 1 ) * sizeof( int ) ); + --top; + } + else + { + ++index; + ++iap; + } + } + return top; +} + +static void +draw_all_rects( XI_OBJ * itf ) +{ + XinRect *ra, + *rap; + XI_ITF_DATA *itf_data; + int count; + int cur_delta_x, + cur_delta_y; + int num_rects; + int ra_count; + int *hml, + *hmlp; + int hml_count, + hml_top; + int *vml, + *vmlp; + int vml_count, + vml_top; + int int_count; + int rect_count; + XinRect client_rect; + XinWindow win = xi_get_window( itf ); + XI_BITMAP *bitmap; + + itf_data = itf->v.itf; + bitmap = itf_data->bitmap; + cur_delta_x = itf_data->delta_x; + cur_delta_y = itf_data->delta_y; + num_rects = count_children( itf ); + XinWindowRectGet( win, &client_rect ); + if ( !num_rects ) + { + if ( bitmap != NULL ) + xi_bitmap_draw( bitmap, win, &client_rect, NULL, TRUE ); + else + XinWindowRectDraw( win, &client_rect ); + return; + } + ra = xi_tree_malloc( sizeof( XinRect ) * num_rects, itf ); + ra_count = 0; + add_rects( itf, ra, &ra_count ); + int_count = num_rects * 2 + 2; + /* hml is an acronym for horizontal mathmatical lines */ + /* vml is an acronym for vertical mathmatical lines */ + hml = xi_tree_malloc( sizeof( int ) * int_count, itf ); + vml = xi_tree_malloc( sizeof( int ) * int_count, itf ); + hmlp = hml; + vmlp = vml; + *hmlp = 0; + ++hmlp; + *vmlp = 0; + ++vmlp; + *hmlp = 9999; + ++hmlp; + *vmlp = 9999; + ++vmlp; + for ( count = 0, rap = ra; count < num_rects; ++count, ++rap ) + { + *hmlp = rap->left; + ++hmlp; + *hmlp = rap->right; + ++hmlp; + *vmlp = rap->top; + ++vmlp; + *vmlp = rap->bottom; + ++vmlp; + } + qsort( ( void * ) hml, ( size_t ) int_count, sizeof( int ), compare ); + qsort( ( void * ) vml, ( size_t ) int_count, sizeof( int ), compare ); + hml_top = elim_dups( hml, int_count ); + vml_top = elim_dups( vml, int_count ); + for ( hml_count = 0, hmlp = hml; hml_count < hml_top; ++hml_count, ++hmlp ) + { + for ( vml_count = 0, vmlp = vml; vml_count < vml_top; ++vml_count, ++vmlp ) + { + /* use static for rect and new_rect, to allow the compiler to generate + * more efficient code */ + static XinRect rect; + + rect.left = *hmlp; + rect.right = *( hmlp + 1 ); + rect.top = *vmlp; + rect.bottom = *( vmlp + 1 ); + for ( rect_count = 0, rap = ra; rect_count < ra_count; ++rect_count, ++rap ) + { + static XinRect new_rect; + + new_rect = *rap; + if ( new_rect.top < rect.top ) + new_rect.top = rect.top; + if ( new_rect.left < rect.left ) + new_rect.left = rect.left; + if ( new_rect.bottom > rect.bottom ) + new_rect.bottom = rect.bottom; + if ( new_rect.right > rect.right ) + new_rect.right = rect.right; + /* if the intersection is not empty, then skip this rectangle */ + if ( new_rect.bottom > new_rect.top && new_rect.right > new_rect.left ) + break; + } + /* if we made it through all rectangles, then no rectangle intersected, + * and we should draw rect */ + if ( ra_count && rect_count == ra_count ) + { + rect.left -= cur_delta_x; + rect.right -= cur_delta_x; + rect.top -= cur_delta_y; + rect.bottom -= cur_delta_y; + if ( bitmap != NULL ) + xi_bitmap_draw( bitmap, win, &client_rect, &rect, TRUE ); + else + XinWindowRectDraw( win, &rect ); + } + } + } + xi_tree_free( ra ); + xi_tree_free( hml ); + xi_tree_free( vml ); +} + +static void +draw_background( XI_OBJ * itf ) +{ + XI_ITF_DATA *itf_data = itf->v.itf; + XinWindow win = itf_data->xin_win; + + if ( itf_data->back_color ) + { + XinDrawTools t; + XinBrush cbrush; + + XinWindowDrawToolsNormalGet( &t ); + XinWindowDrawToolsSet( win, &t ); + XinWindowPenSet( win, &hollow_cpen ); + cbrush.pattern = XinBrushSolid; + cbrush.fore_color = itf_data->back_color; + XinWindowBrushSet( win, &cbrush ); + xi_set_clip( win, NULL ); + draw_all_rects( itf ); + } + else if ( itf_data->bitmap != NULL ) + { + xi_set_clip( win, NULL ); + draw_all_rects( itf ); + } +} + + +static void +do_post_event( XI_OBJ * itf, XinEvent * ep ) +{ + XI_EVENT xiev; + + if ( xi_is_itf( itf ) ) + { + MEMCLEAR( xiev ); + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + xiev.type = XIE_XIN_POST_EVENT; + xiev.v.xin_event = *ep; + } +#ifdef XI_USE_XVT + else + { + if ( ep->type != XinEventCharacter || !ep->v.character.alt ) + { + xiev.type = XIE_XVT_POST_EVENT; + XinXvtEventGet( &xiev.v.xvte ); + } + } +#endif + xiev.refused = FALSE; + if ( !call_cb( itf, &xiev ) ) + return; + } +} + +/* ------------------------------------------------------------------------ */ +/* get_text_ctools */ +/* ------------------------------------------------------------------------ */ +static XinDrawTools * +get_text_ctools( XI_ITF_DATA * itf_data, XinDrawTools * ct, XinFont ** p_font ) +{ + XinWindowDrawToolsNormalGet( ct ); + ct->pen.fore_color = ct->text_fore_color = XI_COLOR_BLACK; + ct->opaque_text = FALSE; + if ( itf_data->font ) + *p_font = itf_data->font; + else + *p_font = xi_get_system_font( ); + return ( ct ); +} + +/* ------------------------------------------------------------------------ */ +/* xi_draw_obj */ +/* ------------------------------------------------------------------------ */ +static void +xi_draw_obj( XI_OBJ * xi_obj ) +{ + XinWindow win; + XI_ITF_DATA *itf_data; + + itf_data = xi_obj->itf->v.itf; + win = itf_data->xin_win; + switch ( xi_obj->type ) + { + case XIT_TEXT: + { + XI_TEXT_DATA *text; + XinDrawTools ct; + XinFont *font; + + text = xi_obj->v.text; + get_text_ctools( itf_data, &ct, &font ); + ct.text_back_color = itf_data->back_color; + ct.text_fore_color = XI_COLOR_BLACK; + if ( text->fore_color ) + ct.text_fore_color = text->fore_color; + if ( text->back_color ) + { + ct.opaque_text = TRUE; + ct.text_back_color = text->back_color; + } + XinWindowDrawToolsSet( win, &ct ); + if ( text->font ) + font = text->font; + if ( ( text->attrib & XI_ATR_ENABLED ) ) + XinWindowColorTextForeSet( win, ct.text_fore_color ); + else + XinWindowColorTextForeSet( win, + ( XinColor ) xi_get_pref( XI_PREF_COLOR_DISABLED ) ); + XinWindowColorTextBackSet( win, ct.text_back_color ); + xi_draw_clipped_text( win, font, text->text, &text->rct, &text->rct, + text->attrib | XI_ATR_VCENTER, FALSE, 0, -1, + text->mnemonic, text->mnemonic_instance, NULL ); + break; + } + case XIT_LINE: + { + XI_LINE_DATA *line; + XinPoint pnt1, + pnt2; + + XinWindowClipSet( win, NULL ); + line = xi_obj->v.line; + if ( line->attrib & XI_ATR_VISIBLE ) + { + pnt1 = line->pnt1; + pnt2 = line->pnt2; + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_3D_LOOK ) ) + xi_draw_3d_line( win, pnt1, pnt2, line->well ); + else + { + XinPen cpen; + + cpen = black_cpen; + if ( line->fore_color ) + cpen.fore_color = line->fore_color; + XinWindowPenSet( win, &cpen ); + if ( line->back_color ) + XinWindowColorTextBackSet( win, line->back_color ); + xi_move_to( win, pnt1 ); + xi_draw_line( win, pnt2 ); + } + } + break; + } + case XIT_RECT: + { + XI_RECT_DATA *rect; + XinRect rct; + + XinWindowClipSet( win, NULL ); + rect = xi_obj->v.rect; + if ( rect->attrib & XI_ATR_VISIBLE ) + { + rct = rect->rct; + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_3D_LOOK ) ) + { + xi_draw_3d_rect( win, &rct, rect->well, 1, + rect->hilight_color, rect->back_color, + rect->shadow_color ); + if ( rect->ridge ) + { + xi_inflate_rect( &rct, -1 ); + xi_draw_3d_rect( win, &rct, ( BOOLEAN ) ( !rect->well ), 1, + rect->hilight_color, rect->back_color, + rect->shadow_color ); + } + } + else + { + XinPen cpen = black_cpen; + XinBrush cbrush = white_cbrush; + + if ( rect->fore_color ) + cpen.fore_color = rect->fore_color; + if ( rect->back_color ) + cbrush.fore_color = rect->back_color; + + XinWindowBrushSet( win, &cbrush ); + + if ( rect->ridge ) + { + XinWindowPenSet( win, &hollow_cpen ); + xi_draw_rect( win, &rct ); + XinWindowPenSet( win, &cpen ); + xi_draw_roundrect( win, &rct, 4, 4 ); + } + else + { + XinWindowPenSet( win, &cpen ); + xi_draw_rect( win, &rct ); + } + } + if ( rect->bitmap != NULL ) + { + xi_inflate_rect( &rct, -1 ); + xi_bitmap_draw( rect->bitmap, win, &rct, NULL, FALSE ); + } + } + break; + } + default: + break; + } +} + +/* ------------------------------------------------------------------------ */ +/* xi_draw_field_button */ +/* ------------------------------------------------------------------------ */ +void +xi_draw_field_button( XI_OBJ * xi_obj ) +{ + XI_FIELD_DATA *fd; + unsigned long attrib; + STX_DATA *stxd; + const XinColor color_light = aga_get_pref(AGA_PREF_BTN_COLOR_LIGHT); + const XinColor color_ctrl = aga_get_pref(AGA_PREF_BTN_COLOR_CTRL); + const XinColor color_dark = aga_get_pref(AGA_PREF_BTN_COLOR_DARK); + const int button_depth = 1; + +#if XIWS != XIWS_WM + XinRect cr, r; + +#endif + XinWindow win; + + attrib = xi_get_attrib( xi_obj ); + if ( !( attrib & XI_ATR_VISIBLE ) ) + return; + fd = xi_obj->v.field; + stxd = ( STX_DATA * ) fd->stx; + win = xi_obj->itf->v.itf->xin_win; + XinWindowDrawModeSet( win, XinDrawModeCopy ); + xi_set_clip( win, NULL ); +#if XIWS != XIWS_WM + r = fd->btn_rct; + xi_inflate_rect( &r, -1 ); + + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_3D_LOOK ) ) + xi_draw_shaded_rect(win, &r, fd->down, button_depth, color_light, color_ctrl, color_dark); + else + { + XinWindowBrushSet( win, &white_cbrush ); + XinWindowPenSet( win, &hollow_cpen ); + xi_draw_rect( win, &r ); + } + + cr = r; + xi_inflate_rect( &cr, -button_depth ); + xi_set_clip( win, &cr ); + if ( fd->button_bitmap != NULL ) + xi_bitmap_draw( fd->button_bitmap, win, &cr, &cr, FALSE ); + else + { + XinColor color = ( BOOLEAN ) xi_get_pref( XI_PREF_3D_LOOK ) ? color_ctrl : xi_get_pref( XI_PREF_COLOR_CTRL ); + // Guy was here: center icon in button + int x = (r.left+r.right-XinMetricGet(XinMetricIconWidth))/2; // x = r.left + 3; + int y = (r.top+r.bottom-XinMetricGet(XinMetricIconHeight))/2; // y = r.top + 2; + + int icon_rid = fd->icon_rid; + if ( icon_rid == 0 ) + icon_rid = ( int ) xi_get_pref( XI_PREF_COMBO_ICON ); + if ( fd->down ) + xi_draw_icon( win, x, y + 1, icon_rid, XI_COLOR_BLACK, color ); + else + xi_draw_icon( win, x, y, icon_rid, XI_COLOR_BLACK, color ); + } + xi_set_clip( win, NULL ); + XinWindowPenSet( win, &black_cpen ); + XinWindowBrushSet( win, &hollow_cbrush ); + xi_draw_rect( win, &fd->btn_rct ); +#endif +#if XIWS == XIWS_WM + NOREF( stxd ); + { + XinBrush black_cbrush; + + black_cbrush = white_cbrush; + black_cbrush.fore_color = XI_COLOR_BLACK; + xi_set_clip( win, NULL ); + XinWindowPenSet( win, &hollow_cpen ); + XinWindowBrushSet( win, &black_cbrush ); + xi_draw_rect( win, &fd->btn_rct ); + } +#endif +} + +/* ------------------------------------------------------------------------ */ +/* field_event */ +/* ------------------------------------------------------------------------ */ +static void +field_event( XI_OBJ * xi_obj, XinEvent * ep ) +{ + XI_FIELD_DATA *field_data; + XinRect rct; + + field_data = xi_obj->v.field; + rct = field_data->btn_rct; + switch ( ep->type ) + { + case XinEventCharacter: + if ( field_data->button ) + { + long button_key; + BOOLEAN shift, + control, + alt; + + button_key = xi_get_pref( XI_PREF_BUTTON_KEY ); + shift = ( BOOLEAN ) ( ( button_key & XI_MOD_SHIFT ) != 0 ); + control = ( BOOLEAN ) ( ( button_key & XI_MOD_CONTROL ) != 0 ); + alt = ( BOOLEAN ) ( ( button_key & XI_MOD_ALT ) != 0 ); + button_key &= 0xffffffL; + if ( button_key == ep->v.character.ch && + shift == ep->v.character.shift && + control == ep->v.character.control && + alt == ep->v.character.alt ) + { + XI_EVENT xiev; + XI_OBJ *itf; + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = xi_obj; + itf = xi_obj->itf; + call_cb( itf, &xiev ); + } + } + break; + case XinEventPaint: + if ( field_data->button ) + xi_draw_field_button( xi_obj ); + break; + case XinEventMouseDown: + { + unsigned long attrib; + + attrib = stx_get_attrib( xi_obj->v.field->stx ); + attrib &= ( XI_ATR_ENABLED | XI_ATR_VISIBLE ); + if ( field_data->button && + attrib == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + { + if ( xi_pt_in_rect( &rct, ep->v.mouse.where ) ) + { + field_data->down = TRUE; + field_data->down_in_btn = TRUE; + xi_draw_field_button( xi_obj ); + xi_set_trap_obj( xi_obj ); + XinWindowMouseTrap( xi_obj->itf->v.itf->xin_win, TRUE ); + } + } + break; + } + case XinEventMouseMove: + if ( field_data->button && field_data->down_in_btn ) + { + if ( xi_pt_in_rect( &rct, ep->v.mouse.where ) && !field_data->down ) + { + field_data->down = TRUE; + xi_draw_field_button( xi_obj ); + } + if ( !xi_pt_in_rect( &rct, ep->v.mouse.where ) && field_data->down ) + { + field_data->down = FALSE; + xi_draw_field_button( xi_obj ); + } + } + break; + case XinEventMouseUp: + if ( field_data->button && field_data->down_in_btn ) + { + XinWindowMouseRelease( ); + if ( field_data->down ) + { + field_data->down = FALSE; + xi_draw_field_button( xi_obj ); + } + field_data->down_in_btn = FALSE; + if ( xi_pt_in_rect( &rct, ep->v.mouse.where ) ) + { + if ( xi_move_focus( xi_obj ) ) + { + XI_EVENT xiev; + XI_OBJ *itf; + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = xi_obj; + itf = xi_obj->itf; + call_cb( itf, &xiev ); + } + } + } + break; + default: + break; + + } +} + +void +xi_draw_foc_and_dflt( XI_OBJ * xi_obj ) +{ + XI_OBJ *dflt_obj, + *foc_obj; + XI_BTN_DATA *bd; + BOOLEAN enabled; + BOOLEAN visible; + BOOLEAN focus; + BOOLEAN dflt; + unsigned long attrib; + + if ( xi_get_native_controls( xi_obj ) ) + return; + dflt_obj = xi_get_default( xi_obj ); + if ( dflt_obj ) + { + bd = dflt_obj->v.btn; + attrib = xi_get_attrib( dflt_obj ); + enabled = ( ( attrib & XI_ATR_ENABLED ) != 0 ); + visible = ( ( attrib & XI_ATR_VISIBLE ) != 0 ); + focus = ( xi_get_focus( dflt_obj->itf ) == dflt_obj ); + dflt = bd->dflt; + xi_draw_button( dflt_obj, &bd->rct, enabled, + visible, focus, bd->down, dflt, bd->checked, FALSE, TRUE ); + } + foc_obj = xi_get_focus( xi_obj ); + if ( foc_obj && foc_obj->type == XIT_BTN && foc_obj != dflt_obj ) + { + bd = foc_obj->v.btn; + attrib = xi_get_attrib( foc_obj ); + enabled = ( ( attrib & XI_ATR_ENABLED ) != 0 ); + visible = ( ( attrib & XI_ATR_VISIBLE ) != 0 ); + focus = TRUE; + dflt = bd->dflt; + xi_draw_button( foc_obj, &bd->rct, enabled, + visible, focus, bd->down, dflt, bd->checked, FALSE, TRUE ); + } +} + +/* ------------------------------------------------------------------------ */ +/* form_event */ +/* ------------------------------------------------------------------------ */ + +static BOOLEAN +form_event( XI_OBJ * xi_obj, XinEvent * ep ) +{ + BOOLEAN retval = FALSE; + XI_OBJ *focus_obj = xi_obj->itf->v.itf->focus_obj; + XI_OBJ *itf = xi_obj->itf; + BOOLEAN focus_is_cell = (focus_obj != NULL && focus_obj->type == XIT_CELL); + + switch ( ep->type ) + { + case XinEventMenuCommand: + /* TODO -- navigation */ + break; + case XinEventCharacter: + { + long c = event_to_longchar( ep ); + XI_OBJ *next_obj = NULL; + + /* navigation character event */ + if ( ( c == '\r' || c == '\n' ) && xi_obj->itf->v.itf->tab_on_enter + && xi_obj->type != XIT_BTN ) + c = xi_get_pref( XI_PREF_FORM_TAB_CHAR ); + if ( c == xi_get_pref( XI_PREF_FORM_TAB_CHAR ) || c == XI_KEY_DOWN ) + { + next_obj = xi_find_next_obj( focus_obj, XI_NEXT_FORM_TAB, c ); + } + else if ( c == xi_get_pref( XI_PREF_FORM_BACKTAB_CHAR ) || + c == XI_KEY_UP ) + { + next_obj = focus_obj; + do + { + next_obj = xi_find_next_obj( next_obj, XI_NEXT_FORM_BACKTAB, c ); + } while ( next_obj != NULL && next_obj != focus_obj && + ( next_obj->type == XIT_FORM || next_obj->type == XIT_CONTAINER ) ); + } + if ( next_obj != NULL ) + { + xi_move_focus_internal( next_obj, TRUE, TRUE, + ( ( c == xi_get_pref( XI_PREF_FORM_TAB_CHAR ) ) || ( c == XI_KEY_DOWN ) ) ? 1 : 2 ); + retval = TRUE; + } + if ( next_obj && (focus_is_cell || xi_is_obj( focus_obj, itf )) ) + xi_draw_foc_and_dflt_if_necessary( focus_obj, next_obj ); + break; + } + default: + break; + } + return retval; +} + +/* ------------------------------------------------------------------------ */ +/* invalidate_button_rect */ +/* ------------------------------------------------------------------------ */ +static BOOLEAN +invalidate_button_rect( XI_OBJ * xi_obj, XI_BTN_DATA * bd, XinRect * rct ) +{ +// if (( bd->type == XIBT_BUTTON || bd->type == XIBT_BUTTON_CHECKBOX || +// bd->type == XIBT_RADIOBTN ) && bd->drawable || bd->type == XIBT_TABBTN) + if ((( bd->type == XIBT_BUTTON || bd->type == XIBT_BUTTON_CHECKBOX || + bd->type == XIBT_RADIOBTN ) && bd->drawable) || bd->type == XIBT_TABBTN) + { + XinRect r; + XinWindow win; + + r = *rct; + xi_inflate_rect( &r, -4 ); + win = xi_get_window( xi_obj->itf ); + xi_invalidate_rect( win, &r ); + XinWindowPaintForce( win ); + return TRUE; + } + return FALSE; +} + +/* ------------------------------------------------------------------------ */ +/* btn_event */ +/* ------------------------------------------------------------------------ */ +static BOOLEAN +btn_event( XI_OBJ * xi_obj, XinEvent * ep ) +{ + BOOLEAN enabled; + BOOLEAN visible; + BOOLEAN focus; + BOOLEAN dflt; + BOOLEAN send_to_form = TRUE; + BOOLEAN ret_val; + XinRect rct; + unsigned long attrib; + XI_BTN_DATA *bd; + + if ( !xi_get_native_controls( xi_obj ) ) + { + attrib = xi_get_attrib( xi_obj ); + enabled = ( ( attrib & XI_ATR_ENABLED ) != 0 ); + visible = ( ( attrib & XI_ATR_VISIBLE ) != 0 ); + focus = ( xi_get_focus( xi_obj->itf ) == xi_obj ); + bd = xi_obj->v.btn; + dflt = bd->dflt; + rct = bd->rct; + switch ( ep->type ) + { + case XinEventTimer: + return FALSE; + case XinEventCharacter: + if ( ep->v.character.ch == ' ' && focus ) + { + XI_EVENT xiev; + XI_OBJ *itf; + int obj_cid; + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = xi_obj; + itf = xi_obj->itf; + obj_cid = xi_obj->cid; + call_cb( itf, &xiev ); + if ( !xi_is_itf( itf ) || xi_get_obj( itf, obj_cid ) == NULL ) + send_to_form = FALSE; + } + break; + case XinEventPaint: + xi_draw_button( xi_obj, &rct, enabled, + visible, focus, bd->down, dflt, bd->checked, FALSE, TRUE ); + break; + case XinEventMouseDouble: + if ( !xi_get_pref( XI_PREF_DBL_PRESSES_BUTTON ) ) + break; + /* else fall through */ + case XinEventMouseDown: + { + XinRect hit_rct; + + if ( ( enabled == FALSE ) || ( visible == FALSE ) ) + break; + hit_rct = rct; + if ( bd->packed == TRUE ) + xi_inflate_rect( &hit_rct, + -( ( int ) xi_get_pref( XI_PREF_CONTAINER_GRID_WIDTH ) ) ); + if ( xi_pt_in_rect( &hit_rct, ep->v.mouse.where ) ) + { + bd->down = TRUE; + bd->down_in_btn = TRUE; + if ( !invalidate_button_rect( xi_obj, bd, &rct ) ) + xi_draw_button( xi_obj, &rct, enabled, visible, focus, bd->down, + dflt, bd->checked, FALSE, FALSE ); + xi_set_trap_obj( xi_obj ); + XinWindowMouseTrap( xi_get_window( xi_obj->itf ), TRUE ); + } + break; + } + case XinEventMouseMove: + if ( bd->down_in_btn ) + { + if ( xi_pt_in_rect( &rct, ep->v.mouse.where ) && !bd->down ) + { + bd->down = TRUE; + if ( !invalidate_button_rect( xi_obj, bd, &rct ) ) + xi_draw_button( xi_obj, &rct, enabled, visible, focus, bd->down, + dflt, bd->checked, FALSE, FALSE ); + } + else if ( !xi_pt_in_rect( &rct, ep->v.mouse.where ) && + bd->down ) + { + bd->down = FALSE; + if ( !invalidate_button_rect( xi_obj, bd, &rct ) ) + xi_draw_button( xi_obj, &rct, + enabled, visible, focus, bd->down, dflt, + bd->checked, FALSE, FALSE ); + } + } + break; + case XinEventMouseUp: + if ( bd->down_in_btn ) + { + bd->down_in_btn = FALSE; + if ( bd->down ) + { + bd->down = FALSE; + if ( !invalidate_button_rect( xi_obj, bd, &rct ) ) + xi_draw_button( xi_obj, &rct, + enabled, visible, focus, bd->down, dflt, + bd->checked, FALSE, FALSE ); + } + XinWindowMouseRelease( ); + if ( ep->type == XinEventMouseUp && + xi_pt_in_rect( &rct, ep->v.mouse.where ) ) + { + XI_EVENT xiev; + XI_OBJ *itf; + int obj_cid; + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = xi_obj; + itf = xi_obj->itf; + obj_cid = xi_obj->cid; + call_cb( itf, &xiev ); + if ( !xi_is_itf( itf ) || xi_get_obj( itf, obj_cid ) == NULL ) + send_to_form = FALSE; + } + } + break; + default: + break; + } + } + ret_val = TRUE; + if ( send_to_form ) + ret_val = form_event( xi_obj, ep ); + return ret_val; +} + +/* ------------------------------------------------------------------------ */ +/* draw_list_button */ +/* ------------------------------------------------------------------------ */ +#define P_OFFSET 3 +static void +draw_list_button( XinWindow win, XinRect * rct, BOOLEAN down ) +{ +#if XIWS != XIWS_WM + int x, + y, + plus_width, + plus_height; + XinPoint p; + XinRect r; + BOOLEAN x2; + + r = *rct; + xi_set_clip( win, NULL ); // XI forgot this! + + XinWindowPenSet( win, &black_cpen ); + XinWindowBrushSet( win, &hollow_cbrush ); + xi_draw_rect( win, &r ); + xi_inflate_rect(&r, -1); + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_3D_LOOK ) ) + { + const XinColor color_light = aga_get_pref(AGA_PREF_BTN_COLOR_LIGHT); + const XinColor color_ctrl = aga_get_pref(AGA_PREF_BTN_COLOR_CTRL); + const XinColor color_dark = aga_get_pref(AGA_PREF_BTN_COLOR_DARK); + + xi_draw_shaded_rect(win, &r, down, 2, color_light, color_ctrl, color_dark); + } + else + { + XinWindowBrushSet( win, &white_cbrush ); + xi_draw_rect( win, &r ); + } + + p.h = rct->left; + p.v = rct->top - 1; + XinWindowPenSet( win, &black_cpen ); + xi_move_to( win, p ); + p.h = rct->right; + xi_draw_line( win, p ); + + plus_width = r.right - r.left; + plus_height = plus_width + 4; + x = r.left + plus_width / 2; + y = r.top + plus_height / 2; + x2 = !( ( r.right + r.left ) % 2 ); + if ( x2 ) + x--; + y--; + XinWindowPenSet( win, &black_cpen ); + + /* draw vertical lines */ + p.h = x; + p.v = r.top + P_OFFSET + down; + xi_move_to( win, p ); + p.v = r.top + plus_height - P_OFFSET + down; + xi_draw_line( win, p ); + p.h = x + 1; + p.v = r.top + P_OFFSET + down; + xi_move_to( win, p ); + p.v = r.top + plus_height - P_OFFSET + down; + xi_draw_line( win, p ); + + /* draw horizontal lines */ + p.v = y + down; + p.h = r.left + P_OFFSET; + xi_move_to( win, p ); + p.h = r.left + plus_width - P_OFFSET; + xi_draw_line( win, p ); + p.v = y + down + 1; + p.h = r.left + P_OFFSET; + xi_move_to( win, p ); + p.h = r.left + plus_width - P_OFFSET; + xi_draw_line( win, p ); +#else + NOREF( rct ); + NOREF( down ); + NOREF( win ); +#endif +} + +/* ------------------------------------------------------------------------ */ +/* list_event */ +/* ------------------------------------------------------------------------ */ +static void +list_event( XI_OBJ * xi_obj, XinEvent * ep ) +{ + XI_LIST_DATA *list_data; + XinRect rct; + LM_DATA *lmp; + + list_data = xi_obj->v.list; + lmp = ( LM_DATA * ) list_data->lm; + if ( lmp->attrib & XI_ATR_VISIBLE ) + { + rct = list_data->sbb_rct; + switch ( ep->type ) + { + case XinEventPaint: + if ( list_data->scroll_bar_button ) + draw_list_button( lmp->win, &rct, list_data->down ); + break; + case XinEventMouseDown: + if ( list_data->scroll_bar_button ) + { + if ( xi_pt_in_rect( &rct, ep->v.mouse.where ) ) + { + list_data->down = TRUE; + list_data->down_in_btn = TRUE; + draw_list_button( lmp->win, &rct, TRUE ); + xi_set_trap_obj( xi_obj ); + XinWindowMouseTrap( xi_obj->itf->v.itf->xin_win, TRUE ); + } + } + break; + case XinEventMouseMove: + if ( list_data->scroll_bar_button && list_data->down_in_btn ) + { + if ( xi_pt_in_rect( &rct, ep->v.mouse.where ) && !list_data->down ) + { + list_data->down = TRUE; + draw_list_button( lmp->win, &rct, TRUE ); + } + if ( !xi_pt_in_rect( &rct, ep->v.mouse.where ) && list_data->down ) + { + list_data->down = FALSE; + draw_list_button( lmp->win, &rct, FALSE ); + } + } + break; + case XinEventMouseUp: + if ( list_data->scroll_bar_button && list_data->down_in_btn ) + { + XinWindowMouseRelease( ); + if ( list_data->down ) + { + list_data->down = FALSE; + draw_list_button( lmp->win, &rct, FALSE ); + } + list_data->down_in_btn = FALSE; + if ( xi_pt_in_rect( &rct, ep->v.mouse.where ) ) + { + XI_EVENT xiev; + XI_OBJ *itf; + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = xi_obj; + itf = xi_obj->itf; + call_cb( itf, &xiev ); + } + } + break; + default: + break; + } + } +} + +/* ------------------------------------------------------------------------ */ +/* itf_event */ +/* ------------------------------------------------------------------------ */ +static BOOLEAN +itf_event( XI_OBJ * xi_obj, XinEvent * ep ) +{ + BOOLEAN retval = FALSE; + XI_ITF_DATA *itf_data; + XI_OBJ *focus_obj; + + itf_data = xi_obj->itf->v.itf; + focus_obj = itf_data->focus_obj; + switch ( ep->type ) + { + case XinEventMenuCommand: + /* TODO -- navigation */ + break; + case XinEventResize: + if ( itf_data->bitmap != NULL + && xi_bitmap_draw_all_on_resize( itf_data->bitmap ) ) + XinWindowRectInvalidate( xi_get_window( xi_obj ), NULL ); + break; + case XinEventCharacter: + { + long c = event_to_longchar( ep ); + XI_OBJ *next_obj = NULL; + + if ( focus_obj->itf != xi_obj ) + XinError( 20030, XinSeverityFatal, 0L ); + + /* navigation character event */ + if ( c == xi_get_pref( XI_PREF_ITF_TAB_CHAR ) ) + next_obj = xi_find_next_obj( focus_obj, XI_NEXT_ITF_TAB, c ); + else if ( c == xi_get_pref( XI_PREF_ITF_BACKTAB_CHAR ) ) + next_obj = xi_find_next_obj( focus_obj, XI_NEXT_ITF_BACKTAB, + c ); + else if ( c == xi_get_pref( XI_PREF_FORM_TAB_CHAR ) && + focus_obj->type == XIT_ITF ) + next_obj = xi_search_itf( focus_obj, XI_SEARCH_FOR_FOCUSABLE, + 0 ); + if ( c == '\r' || c == '\n' ) + { + XI_OBJ *dflt_obj; + + dflt_obj = xi_get_default( xi_obj->itf ); + if ( dflt_obj && ( xi_get_attrib( dflt_obj ) & ( XI_ATR_ENABLED + | XI_ATR_VISIBLE ) ) == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + { + XI_EVENT xiev; + XI_OBJ *itf; + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = dflt_obj; + itf = xi_obj->itf; + call_cb( itf, &xiev ); + retval = TRUE; + } + } + if ( c == '\033' ) + { + XI_OBJ *cancel_obj; + + cancel_obj = xi_get_cancel( xi_obj->itf ); + if ( cancel_obj && ( xi_get_attrib( cancel_obj ) & ( XI_ATR_ENABLED + | XI_ATR_VISIBLE ) ) == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + { + XI_EVENT xiev; + XI_OBJ *itf; + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = cancel_obj; + itf = xi_obj->itf; + call_cb( itf, &xiev ); + retval = TRUE; + } + } + if ( ep->v.character.alt ) + { + XI_OBJ *obj; + + obj = xi_get_obj_from_mnemonic( xi_obj->itf, ( char ) ep->v.character.ch ); + if ( obj ) + { + switch ( obj->type ) + { + case XIT_BTN: + { + XI_EVENT xiev; + XI_OBJ *itf; + + MEMCLEAR( xiev ); + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = obj; + itf = xi_obj->itf; + call_cb( itf, &xiev ); + ep->v.character.consumed = TRUE; + break; + } + case XIT_FIELD: + xi_move_focus( obj ); + ep->v.character.consumed = TRUE; + break; + default: + break; + } + } + } + if ( next_obj != NULL ) + { + xi_move_focus_internal( next_obj, TRUE, FALSE, 0 ); + retval = TRUE; + } + /* if the last focus was a button, and the current focus is not, or if + * the last focus was not a button, and the current focus is, then draw + * the default button, followed by the focus button. */ + if ( xi_is_itf( xi_obj ) ) + { + xi_draw_foc_and_dflt_if_necessary( focus_obj, next_obj ); + } + break; + } + default: + break; + } + return ( retval ); +} + +/* ------------------------------------------------------------------------ */ +/* draw_rectangles */ +/* ------------------------------------------------------------------------ */ +static void +draw_rectangles( XI_OBJ* itf ) +{ + int num, num_members, num_rects, sorted_rects, rect_num; + XI_OBJ** objlist; + XI_OBJ** cur_obj; + XI_OBJ** rect_list; + + /* Count the rectangles in the interface */ + objlist = xi_get_member_list( itf, &num_members ); + num_rects = 0; + for ( num = 0, cur_obj = objlist; num < num_members; num++, cur_obj++ ) + if ( (*cur_obj)->type == XIT_RECT ) + num_rects++; + if ( num_rects == 0 ) + return; + + /* Sort rectangles into proper drawing order */ + rect_list = (XI_OBJ**)xi_tree_malloc( num_rects * sizeof(XI_OBJ*), NULL ); + sorted_rects = 0; + for ( num = 0, cur_obj = objlist; num < num_members; num++, cur_obj++ ) + if ( (*cur_obj)->type == XIT_RECT ) + { + for ( rect_num = 0; rect_num < sorted_rects; rect_num++ ) + { + XinRect intersect; + XinRect* sort_rect = &rect_list[ rect_num ]->v.rect->rct; + XinRectIntersect( &intersect, sort_rect, &(*cur_obj)->v.rect->rct ); + if ( intersect.top == sort_rect->top && intersect.bottom == sort_rect->bottom + && intersect.left == sort_rect->left && intersect.right == sort_rect->right ) + break; + } + if ( rect_num == sorted_rects ) + rect_list[ sorted_rects++ ] = *cur_obj; + else + { + memmove( rect_list + rect_num + 1, rect_list + rect_num, + ( sorted_rects - rect_num ) * sizeof(XI_OBJ*) ); + rect_list[ rect_num ] = *cur_obj; + sorted_rects++; + } + } + + /* Draw rectangles in sorted order */ + for ( num = 0; num < num_rects; num++ ) + xi_draw_obj( rect_list[ num ] ); +} + +/* ------------------------------------------------------------------------ */ +/* xi_send_event */ +/* ------------------------------------------------------------------------ */ + +static int +xi_send_event( XI_OBJ * xi_obj, XinEvent * ep, BOOLEAN do_subtree ) +{ + int n; + XI_OBJ **objlist; + BOOLEAN send_to_parent = FALSE; + int retval = 0; + + switch ( xi_obj->type ) + { + case XIT_TEXT: + case XIT_LINE: + if ( ep->type == XinEventPaint ) + xi_draw_obj( xi_obj ); + break; + case XIT_FIELD: + field_event( xi_obj, ep ); + retval = stx_event( xi_obj->v.field->stx, ep ); + send_to_parent = !retval; + + /* don't send any character events (for navigation to the parent if + * pasting */ + if ( ep->type == XinEventCharacter && xi_obj->itf->v.itf->pasting ) + send_to_parent = FALSE; + break; + case XIT_CONTAINER: + send_to_parent = TRUE; + break; + case XIT_FORM: + send_to_parent = !form_event( xi_obj, ep ); + break; + case XIT_BTN: + send_to_parent = !btn_event( xi_obj, ep ); + break; + case XIT_LIST: + { + XI_OBJ *itf; + + itf = xi_obj->itf; + if ( xi_obj->itf->v.itf->update_obj ) + { + lm_event( itf, xi_obj->v.list->lm, ep ); + send_to_parent = FALSE; + do_subtree = FALSE; + } + else + { + list_event( xi_obj, ep ); + retval = lm_event( itf, xi_obj->v.list->lm, ep ); + send_to_parent = !retval; + /* Don't broadcast events to columns */ + do_subtree = FALSE; + } + if ( xi_is_itf( itf ) ) + if ( xi_obj->itf->v.itf->pasting ) + send_to_parent = FALSE; + break; + } + case XIT_ITF: + itf_event( xi_obj, ep ); + break; + case XIT_CELL: + /* Send events to list as there is no handler for individual cells */ + send_to_parent = TRUE; + break; + case XIT_COLUMN: + default: + /* ignored */ + break; + } + if ( do_subtree && xi_obj->type != XIT_GROUP ) + { + int retval; + XI_OBJ *itf = xi_obj->itf; + + if ( xi_obj->type == XIT_ITF && ep->type == XinEventPaint ) + draw_rectangles( xi_obj ); + + /* loop over sub-objects */ + objlist = xi_get_member_list( xi_obj, &n ); + for ( ; n > 0; n--, objlist++ ) + { + retval = xi_send_event( *objlist, ep, do_subtree ); + if (!xi_is_itf( itf )) + return retval; + /* after everything else is drawn, then if focus is on a button, draw it, + * and if there is a default button, draw it. */ + if ( retval ) + { + if ( xi_obj->type == XIT_ITF && ep->type == XinEventPaint ) + xi_draw_foc_and_dflt( xi_obj ); + return retval; + } + } + if ( xi_obj->type == XIT_ITF && ep->type == XinEventPaint ) + xi_draw_foc_and_dflt( xi_obj ); + } + if ( send_to_parent ) + { + retval = xi_send_event( xi_obj->parent, ep, FALSE ); + return retval; + } + return retval; +} + +void +xi_event( XinWindow win, XinEvent * ep ) +{ + XI_OBJ *itf; + XI_EVENT xiev; + XI_ITF_DATA *itf_data; + BOOLEAN retval; + XinCursor new_cursor; + + if ( win == XI_NULL_WINDOW ) + win = XinWindowFocusGet( ); + if ( win == XI_NULL_WINDOW ) + return; + if ( ( itf = xi_get_itf( win ) ) == NULL ) + { + if ( ep->type == XinEventCreate && xi_creating_itf != NULL ) + { + xi_finish_interface_create( win ); + xi_creating_itf = NULL; + if ( ( itf = xi_get_itf( win ) ) == NULL ) + return; + if ( itf->v.itf->dequeue == XI_DEQUEUE_INIT && itf->v.itf->modal_wait ) + { + xi_dequeue( ); + itf->v.itf->dequeue = XI_DEQUEUE_COMPLETE; + } + } + else + return; + } + itf_data = itf->v.itf; + + MEMCLEAR( xiev ); + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + xiev.type = XIE_XIN_EVENT; + xiev.v.xin_event = *ep; + } +#ifdef XI_USE_XVT + else + { + xiev.type = XIE_XVT_EVENT; + XinXvtEventGet( &xiev.v.xvte ); + } +#endif + xiev.refused = FALSE; + if ( !call_cb( itf, &xiev ) ) + return; + if ( xiev.refused ) + return; + + /* RGM: Do we need to allow the event to change with R3 support? */ + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + *ep = xiev.v.xin_event; + + if ( ep->type == XinEventMouseUp ) + XinWindowMouseRelease( ); + + if ( !xi_eh( win, ep ) ) + return; + + if ( itf_data->dequeue == XI_DEQUEUE_CALL && !itf_data->modal_wait ) + { + xi_dequeue( ); + itf_data->dequeue = XI_DEQUEUE_COMPLETE; + if (itf_data->needs_update) + XinWindowRectInvalidate( itf_data->xin_win, NULL ); + } + MEMCLEAR( xiev ); + switch ( ep->type ) + { + case XinEventTimer: + { + xi_send_event( itf, ep, TRUE ); + break; + } + case XinEventPaint: + { + if ( itf_data->dequeue != XI_DEQUEUE_COMPLETE ) + { + itf_data->needs_update = TRUE; + do_post_event( itf, ep ); + return; + } + if ( itf_data->update_obj ) + { + xi_send_event( itf_data->update_obj, ep, FALSE ); + itf_data->update_obj = NULL; + } + else + { + itf->v.itf->half_baked = FALSE; + draw_background( itf ); + + xi_send_event( itf, ep, TRUE ); + } + break; + } + case XinEventMouseDown: + case XinEventMouseDouble: + { + XI_OBJ *itf2; + + itf2 = itf; + itf_data->mouse_is_down = TRUE; + xi_send_event( itf, ep, TRUE ); + if ( xi_is_itf( itf2 ) ) + if ( !itf_data->trap_explicit ) + itf_data->trap_obj = itf_data->focus_obj; + break; + } + case XinEventCharacter: + if ( ep->v.character.ch == XI_KEY_BTAB ) + ep->v.character.shift = FALSE; + if ( itf_data->focus_obj != NULL ) + xi_send_event( itf_data->focus_obj, ep, FALSE ); + update_menus( ); + break; + case XinEventResize: + xi_send_event( itf, ep, TRUE ); + break; + case XinEventMouseUp: +#ifndef NO_PRIMARY_SELECTION +#if XIWS == XIWS_XM + if ( ep->v.mouse.button == 2 ) + get_primary_selection( itf, win ); +#endif +#endif + itf_data->mouse_is_down = FALSE; + if ( xi_get_drag_list_obj( ) ) + lm_event( itf, xi_get_drag_list_obj( )->v.list->lm, ep ); + else if ( itf_data->trap_obj != NULL ) + xi_send_event( itf_data->trap_obj, ep, FALSE ); + if ( xi_is_itf( itf ) ) + { + itf_data->trap_obj = NULL; + itf_data->trap_explicit = FALSE; + update_menus( ); + } + break; + case XinEventMouseMove: + if ( xi_get_drag_list_obj( ) ) + lm_event( itf, xi_get_drag_list_obj( )->v.list->lm, ep ); + else if ( itf_data->trap_obj != NULL ) + xi_send_event( itf_data->trap_obj, ep, FALSE ); + else + { + if ( !itf_data->mouse_is_down ) + { + retval = xi_send_event( itf, ep, TRUE ); + switch ( retval ) + { + case 0: + new_cursor = XI_CURSOR_ARROW; + break; + case 1: + new_cursor = XI_CURSOR_IBEAM; + break; + case 2: + new_cursor = ( XinCursor) xi_get_pref( XI_PREF_SIZE_CURSOR_RID ); + break; + case 3: + new_cursor = ( XinCursor ) xi_get_pref( XI_PREF_HAND_CURSOR_RID ); + break; + case 4: + new_cursor = XI_CURSOR_CROSS; + break; + case 5: + new_cursor = XI_CURSOR_ARROW; + break; + case 6: + new_cursor = + ( XinCursor ) xi_get_pref( XI_PREF_VSIZE_CURSOR_RID ); + break; + default: + new_cursor = XI_CURSOR_ARROW; + break; + } + if ( itf_data->cursor != new_cursor && !itf_data->cursor_override ) + { + XinWindowCursorSet( itf_data->xin_win, new_cursor ); + itf_data->cursor = new_cursor; + } + } + } + break; + case XinEventMenuCommand: + { + XinWindow win; + + xiev.v.cmd.tag = ep->v.menu_command.tag; + xiev.v.cmd.shift = ep->v.menu_command.shift; + xiev.v.cmd.control = ep->v.menu_command.control; + xiev.type = XIE_COMMAND; + win = itf_data->xin_win; + call_cb( itf, &xiev ); + if ( xi_is_window( win ) ) + if ( itf_data->focus_obj != NULL ) + xi_send_event( itf_data->focus_obj, ep, FALSE ); + } + if ( xi_is_itf( itf ) ) + do_edit_menu( itf, ep ); + break; + case XinEventFocus: + update_menus( ); + break; + case XinEventDestroy: + { + itf->v.itf->in_event_destroy = TRUE; + destroy_controls( itf ); +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + xi_xvt_tx_event( win, ep ); +#endif + xiev.type = XIE_CLEANUP; + xiev.v.xi_obj = itf; + call_cb( itf, &xiev ); + xi_remove_window_from_list( win ); + + /* free the whole interface tree */ + xi_tree_free( ( char * ) itf ); + break; + } + case XinEventCloseButton: + xiev.type = XIE_CLOSE; + xiev.v.xi_obj = itf; + call_cb( itf, &xiev ); + if ( xi_is_itf( itf ) && !xiev.refused ) + xi_delete( itf ); + break; + case XinEventQuit: + if ( ep->v.quit.query ) + XinAppQuitOk( ); + else + XinAppTerminate( ); + break; + case XinEventHScroll: + case XinEventVScroll: + /* handle XinEventHScroll, etc if list is using window scroll bars */ + break; + case XinEventControl: + control_event( itf, win, ep ); + update_menus( ); + break; + case XinEventHelp: + { + XI_OBJ *focus = xi_get_focus( itf ); + if (focus != NULL && focus->help_key != NULL) + XinNativeHelp( win, focus->help_key ); + else if ( itf->help_key != NULL ) + XinNativeHelp( win, itf->help_key ); + break; + } + default: + break; + } + + if ( ep->type == XinEventPaint ) + { + /* send XVT event */ + MEMCLEAR( xiev ); + xiev.type = XIE_UPDATE; + xiev.v.xin_event = *ep; + xiev.refused = FALSE; + call_cb( itf, &xiev ); + xi_set_clip( xi_get_window( itf ), NULL ); + } + + do_post_event( itf, ep ); +} + +long +xi_get_app_data( XI_OBJ * xi_obj ) +{ + return ( xi_obj->app_data ); +} + +long +xi_get_app_data2( XI_OBJ * xi_obj ) +{ + return ( xi_obj->app_data2 ); +} + +unsigned long +xi_get_attrib( XI_OBJ * xi_obj ) +{ + switch ( xi_obj->type ) + { +case XIT_COLUMN: + return ( lm_get_attrib( xi_obj->parent->v.list->lm, LM_COLUMN, + xi_obj_to_idx( xi_obj ), 0, FALSE ) ); + case XIT_LIST: + return ( lm_get_attrib( xi_obj->v.list->lm, LM_LIST, 0, 0, FALSE ) ); + case XIT_ROW: + return ( lm_get_attrib( xi_obj->parent->v.list->lm, LM_ROW, + xi_obj->v.row, 0, FALSE ) ); + case XIT_CELL: + return ( lm_get_attrib( xi_obj->parent->v.list->lm, LM_CELL, + xi_obj->v.cell.row, xi_obj->v.cell.column, + xi_obj->v.cell.is_vert_scrolled ) ); + case XIT_BTN: + return ( xi_obj->v.btn->attrib ); + case XIT_CONTAINER: + /* pretend that containers have attributes, and that they are always + * visible and enabled */ + return XI_ATR_ENABLED | XI_ATR_VISIBLE; + case XIT_FORM: + return ( xi_obj->v.form->attrib ); + case XIT_FIELD: + return ( stx_get_attrib( xi_obj->v.field->stx ) ); + case XIT_TEXT: + return ( xi_obj->v.text->attrib ); + case XIT_LINE: + return ( xi_obj->v.line->attrib ); + case XIT_RECT: + return ( xi_obj->v.rect->attrib ); + case XIT_GROUP: + return 0L; + default: + XinError( 20018, XinSeverityFatal, 0L ); + } + return 0L; +} + +XI_OBJ * +xi_get_focus( XI_OBJ * itf ) +{ + XinWindow win; + + if ( itf != NULL ) + return ( itf->v.itf->focus_obj ); + else if ( ( win = XinWindowFocusGet( ) ) == XI_NULL_WINDOW ) + return ( NULL ); + else if ( xi_is_window( win ) ) + { + XI_OBJ *itf; + + itf = xi_get_itf( win ); + return ( itf->v.itf->focus_obj ); + } + else + return ( NULL ); +} + +long * +xi_get_list_info( XI_OBJ * xi_obj, int *nbr_recs ) +{ + if ( xi_obj->type != XIT_LIST ) + XinError( 20020, XinSeverityFatal, 0L ); + return lm_get_list_info( xi_obj->v.list->lm, nbr_recs ); +} + +XI_OBJ ** +xi_get_member_list( XI_OBJ * xi_obj, int *nbr_members ) +{ + int i; + XI_OBJ *obj; + XI_GROUP_DATA *groupdata; + + if ( xi_obj->type == XIT_GROUP ) + { + groupdata = xi_obj->v.group; + if ( groupdata->objlist != NULL ) + xi_tree_free( groupdata->objlist ); + groupdata->objlist = + ( XI_OBJ * * ) xi_tree_malloc( sizeof( XI_OBJ * ) * groupdata->nbr_cids, xi_obj ); + *nbr_members = 0; + for ( i = 0; i < groupdata->nbr_cids; i++ ) + { + obj = xi_get_obj( xi_obj->itf, groupdata->cidlist[i] ); + if ( obj != NULL ) + { + groupdata->objlist[*nbr_members] = obj; + ( *nbr_members )++; + } + } + return ( groupdata->objlist ); + } + else + { + *nbr_members = xi_obj->nbr_children; + return ( xi_obj->children ); + } +} + +/* +xi_get_obj: retrieve an XI_OBJ from the interface tree given its cid. +Although externally documented to work only on XIT_ITF, +this will start searching at any point in the interface tree. + +xi_get_obj will ignore NULL objects so it can be used in the middle +of creating an interface tree. +*/ +XI_OBJ * +xi_get_obj( XI_OBJ * obj, int cid ) +{ + XI_OBJ **objlist; + XI_OBJ *temp; + int n; + + if ( obj->cid == cid ) + return ( obj ); + + switch ( obj->type ) + { + case XIT_GROUP: + case XIT_CELL: + case XIT_ROW: + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_ASSERT_ON_NULL_CID ) ) + XinError( 30207, XinSeverityFatal, 0L ); + return ( NULL ); + default: + break; + } + + /* search in child list */ + objlist = xi_get_member_list( obj, &n ); + for ( ; n > 0; n--, objlist++ ) + { + /* call recursively for generality in future versions */ + if ( ( temp = xi_get_obj( *objlist, cid ) ) != NULL ) + return ( temp ); + } + return ( NULL ); +} + +XinRect * +xi_get_rect( XI_OBJ * xi_obj, XinRect * rctp ) +{ + return xi_get_rect_internal( xi_obj, rctp, NULL, NULL ); +} + +XinRect * +xi_get_rect_internal( XI_OBJ * xi_obj, XinRect * rctp, XinRect * old_win_rct, XinRect * new_win_rct ) +{ + XI_OBJ **objp; + XinRect rct; + int i, + n; + + switch ( xi_obj->type ) + { + case XIT_CONTAINER: + *rctp = xi_obj->v.container->rct; + break; + case XIT_BTN: + *rctp = xi_obj->v.btn->rct; + break; + case XIT_COLUMN: + lm_get_rect( xi_obj->parent->v.list->lm, LM_COLUMN, + xi_obj_to_idx( xi_obj ), rctp ); + break; + case XIT_ROW: + if ( xi_obj->v.row_data.is_vert_scrolled ) + memset( ( char * ) rctp, 0, sizeof( *rctp ) ); + else + { + lm_get_rect( xi_obj->parent->v.list->lm, LM_ROW, + xi_obj->v.row, rctp ); + } + break; + case XIT_LIST: + lm_get_rect( xi_obj->v.list->lm, LM_LIST, 0, rctp ); + if ( xi_obj->v.list->scroll_bar ) + { + xi_get_sb_rect( xi_obj, &rct ); + rctp->right = rct.right; + } + if ( xi_obj->v.list->width ) + { + xi_get_hsb_rect( xi_obj, &rct ); + rctp->bottom = rct.bottom; + } + if ( old_win_rct ) + { + rctp->bottom = ( int ) ( ( long ) rctp->bottom * new_win_rct->bottom / old_win_rct->bottom ); + rctp->right = ( int ) ( ( long ) rctp->right * new_win_rct->right / old_win_rct->right ); + } + break; + case XIT_ITF: + case XIT_FORM: + { + BOOLEAN first_rect = TRUE; + + objp = xi_obj->children; + n = xi_obj->nbr_children; + for ( i = 0; i < n; objp++, i++ ) + { + if ( xi_get_rect_internal( *objp, &rct, old_win_rct, new_win_rct ) != NULL ) + { + if ( first_rect ) + { + first_rect = FALSE; + *rctp = rct; + } + else + XinRectEnclose( rctp, &rct, rctp ); + } + } + break; + } + case XIT_FIELD: + { + XI_FIELD_DATA *fd; + + fd = xi_obj->v.field; + stx_get_rect( fd->stx, rctp ); + if ( fd->button ) + { + if ( fd->button_on_left ) + rctp->left = fd->btn_rct.left; + else + rctp->right = fd->btn_rct.right; + } + break; + } + case XIT_TEXT: + *rctp = xi_obj->v.text->rct; + break; + case XIT_RECT: + *rctp = xi_obj->v.rect->rct; + break; + case XIT_LINE: + { + XI_LINE_DATA *line; + + line = xi_obj->v.line; + rctp->top = min( line->pnt1.v, line->pnt2.v ); + rctp->bottom = max( line->pnt1.v, line->pnt2.v ); + rctp->left = min( line->pnt1.h, line->pnt2.h ); + rctp->right = max( line->pnt1.h, line->pnt2.h ); + break; + } + case XIT_GROUP: + /* bounding rect is undefined */ + return ( NULL ); + case XIT_CELL: + { + XI_OBJ row; + XI_OBJ *col; + XI_OBJ **members; + int nbr_members; + int row_nbr, + col_nbr; + XinRect row_rct, + col_rct; + + if ( xi_obj->v.cell.is_vert_scrolled ) + memset( ( char * ) rctp, 0, sizeof( *rctp ) ); + else + { + row_nbr = xi_obj->v.cell.row; + col_nbr = xi_obj->v.cell.column; + XI_MAKE_ROW( &row, xi_obj->parent, row_nbr ); + xi_get_rect_internal( &row, &row_rct, old_win_rct, new_win_rct ); + members = xi_get_member_list( xi_obj->parent, &nbr_members ); + col = members[col_nbr]; + xi_get_rect_internal( col, &col_rct, old_win_rct, new_win_rct ); + xi_rect_intersect( rctp, &row_rct, &col_rct ); + } + break; + } + default: + XinError( 20021, XinSeverityFatal, 0L ); + } + return ( rctp ); +} + +void +xi_set_rect_internal( XI_OBJ * xi_obj, XinRect * rctp ) +{ + switch ( xi_obj->type ) + { + case XIT_CONTAINER: + { + xi_container_set_rect_internal( xi_obj, rctp ); + break; + } + case XIT_BTN: + xi_obj->v.btn->rct = *rctp; + break; + case XIT_LIST: + lm_set_rect( xi_obj->v.list->lm, rctp ); + break; + case XIT_FIELD: + { + xi_field_set_rect_internal( xi_obj, rctp ); + break; + } + case XIT_TEXT: + xi_obj->v.text->rct = *rctp; + break; + case XIT_RECT: + xi_obj->v.rect->rct = *rctp; + break; + case XIT_LINE: + { + /* We generate a point which is the change between old and new. */ + XI_LINE_DATA *line; + XinPoint point; + + line = xi_obj->v.line; + point.v = min( line->pnt1.v, line->pnt2.v ); + point.v = rctp->top - point.v; + point.h = min( line->pnt1.h, line->pnt2.h ); + point.h = rctp->left - point.h; + line->pnt1.v += point.v; + line->pnt1.h += point.h; + line->pnt2.v += point.v; + line->pnt2.h += point.h; + break; + } + default: + XinError( 20032, XinSeverityFatal, 0L ); + } +} + +void +xi_set_rect( XI_OBJ * xi_obj, XinRect * rctp, BOOLEAN do_invalidates ) +{ + XinRect old_rect; + XinWindow win = 0L; + if (do_invalidates) + { + win = xi_get_window( xi_obj ); + xi_get_rect_internal( xi_obj, &old_rect, NULL, NULL ); + XinWindowRectInvalidate( win, &old_rect ); + } + + xi_set_rect_internal( xi_obj, rctp ); + + if (do_invalidates) + { + xi_get_rect_internal( xi_obj, &old_rect, NULL, NULL ); + XinWindowRectInvalidate( win, &old_rect ); + } +} + +void +xi_get_sel( XI_OBJ * xi_obj, int *selstart, int *selstop ) +{ + XI_OBJ *focus_obj; + BOOLEAN is_focus; + + focus_obj = xi_get_focus( xi_obj->itf ); + /* check if the passed object is the focus object */ + if ( focus_obj == NULL ) + is_focus = FALSE; /* no focus */ + else if ( focus_obj == xi_obj ) + is_focus = TRUE; /* object is the focus object */ + else if ( focus_obj->type != XIT_CELL || xi_obj->type != XIT_CELL ) + is_focus = FALSE; /* objects are not both cells */ + else /* both objects are temporary cell objects */ + is_focus = ( xi_obj->v.cell.row == focus_obj->v.cell.row + && xi_obj->v.cell.column == focus_obj->v.cell.column ); + /* it's the focus if the row & column are */ + /* the same */ + if ( !is_focus ) + { + /* selection is only valid for focus object */ + *selstart = *selstop = 0; + return; + } + switch ( xi_obj->type ) + { + case XIT_CELL: + if ( focus_obj->v.cell.is_vert_scrolled ) + lm_focus_cell_selection_get( ( LM_DATA * ) xi_obj->parent->v.list->lm, selstart, selstop ); + else + lm_get_sel( xi_obj->parent->v.list->lm, selstart, selstop ); + break; + case XIT_FIELD: + stx_get_sel( xi_obj->v.field->stx, selstart, selstop ); + break; + case XIT_COLUMN: + case XIT_ITF: + case XIT_LIST: + case XIT_ROW: + case XIT_BTN: + case XIT_FORM: + case XIT_GROUP: + case XIT_TEXT: + XinError( 20022, XinSeverityFatal, 0L ); + break; + default: + break; + } +} + +char * +xi_get_text( XI_OBJ * xi_obj, char *s, int len ) +{ + char *b; + + b = NULL; + switch ( xi_obj->type ) + { + case XIT_CELL: + b = lm_get_text( xi_obj->parent->v.list->lm, s, len, + xi_obj->v.cell.row, xi_obj->v.cell.column, xi_obj->v.cell.is_vert_scrolled ); + break; + case XIT_COLUMN: + b = lm_get_text( xi_obj->parent->v.list->lm, s, len, + LM_HEADING_TEXT, xi_obj_to_idx( xi_obj ), FALSE ); + break; + case XIT_ITF: + b = XinWindowTitleGet( xi_obj->v.itf->xin_win ); + break; + case XIT_ROW: + XinError( 20023, XinSeverityFatal, 0L ); + case XIT_BTN: + b = xi_obj->v.btn->text; + break; + case XIT_FIELD: + b = stx_get_text( xi_obj->v.field->stx, s, len ); + break; + case XIT_TEXT: + { + XI_TEXT_DATA *text_data; + + text_data = xi_obj->v.text; + b = text_data->text; + } + break; + case XIT_LIST: + case XIT_GROUP: + case XIT_FORM: + if ( s ) + *s = '\0'; + break; + default: + break; + } + if ( s && b ) + tstrncpy( s, b, len ); + return b; +} + +XinWindow +xi_get_window( XI_OBJ * xi_obj ) +{ + return ( xi_obj->itf->v.itf->xin_win ); +} + +/*------------------------------------------------------------------------- +function: xi_scroll_rec +xi_obj: list object to scroll. Must be a list object. +rec: first record to go to +color: color of row +attrib: attribute of row +-------------------------------------------------------------------------*/ +int +xi_scroll_rec( XI_OBJ * xi_obj, long rec, XinColor color, unsigned long attrib, int row_height ) +{ + LM_SCROLL_ARG arg; + + if ( xi_obj->type != XIT_LIST ) + XinError( 20024, XinSeverityFatal, 0L ); + xi_obj->v.list->done_initial_xi_scroll = TRUE; + MEMCLEAR( arg ); + arg.lm = xi_obj->v.list->lm; + /* arg.nbr_lines = 0; arg.percent = 0; arg.same_cell = 0; */ + arg.rec = rec; + arg.have_rec = TRUE; + arg.color = color; + arg.attrib = attrib; + arg.row_height = row_height; + arg.rec_at_top = TRUE; + return lm_scroll( &arg ); +} + +/* +typedef struct _xi_scroll_record_arg +{ + XI_OBJ* xi_obj; + long record; + COLOR row_color; + unsigned long attrib; + int row_height; + BOOLEAN rec_at_top; +} XI_SCROLL_RECORD_ARG; +*/ +int +xi_scroll_record( XI_SCROLL_RECORD_ARG * arg ) +{ + LM_SCROLL_ARG lm_scroll_arg; + XI_OBJ *xi_obj = arg->xi_obj; + + xi_obj->v.list->done_initial_xi_scroll = TRUE; + MEMCLEAR( lm_scroll_arg ); + lm_scroll_arg.lm = xi_obj->v.list->lm; + /* lm_scroll_arg.nbr_lines = 0; lm_scroll_arg.percent = 0; + * lm_scroll_arg.same_cell = 0; */ + lm_scroll_arg.rec = arg->record; + lm_scroll_arg.have_rec = TRUE; + lm_scroll_arg.color = arg->row_color; + lm_scroll_arg.attrib = arg->attrib; + lm_scroll_arg.row_height = arg->row_height; + lm_scroll_arg.rec_at_top = arg->rec_at_top; + return lm_scroll( &lm_scroll_arg ); +} + +/*------------------------------------------------------------------------- +function: xi_scroll_internal +xi_obj: list object to scroll. Must be a list object. +nbr_lines: nbr of lines to scroll, may be positive or negative, may be set + to XI_SCROLL_FIRST, XI_SCROLL_LAST, XI_SCROLL_PGUP, or XI_SCROLL_PGDN +percent: passed with XI_SCROLL_FIRST event +same_cell: sometimes the focus goes back onto the same cell. In other cases, + for instance, XI_SCROLL_FIRST, XI_SCROLL_LAST, XI_SCROLL_PGUP, and + XI_SCROLL_PGDN, we don't want to put the focus back on the same cell, + but instead, want to put the focus on the first or last fully visible + row. +invalidate: indicates whether to invalidate the list. This is only set to FALSE when xi_scroll_internal is + called when the interface is created. +-------------------------------------------------------------------------*/ +int +xi_scroll_internal( XI_OBJ * xi_obj, int nbr_lines, int percent, + BOOLEAN same_cell ) +{ + LM_SCROLL_ARG arg; + + if ( xi_obj->type != XIT_LIST ) + XinError( 20037, XinSeverityFatal, 0L ); + xi_obj->v.list->done_initial_xi_scroll = TRUE; + MEMCLEAR( arg ); + arg.lm = xi_obj->v.list->lm; + arg.nbr_lines = nbr_lines; + arg.percent = percent; + arg.same_cell = same_cell; + arg.rec_at_top = TRUE; + /* arg.rec = 0; arg.have_rec = FALSE; arg.color = 0L; arg.attrib = 0L; + * arg.row_height = 0; */ + return lm_scroll( &arg ); +} + +BOOLEAN +xi_delete_row( XI_OBJ * xi_obj ) +{ + int row; + XI_OBJ *list_obj; + BOOLEAN rv; + + if ( xi_obj->type != XIT_ROW ) + XinError( 20025, XinSeverityFatal, 0L ); + list_obj = xi_obj->parent; + row = xi_obj->v.row; + rv = lm_delete_row( list_obj->v.list->lm, row ); + return rv; +} + +BOOLEAN +xi_insert_row( XI_OBJ * list, int row ) +{ + BOOLEAN rv; + + if ( list->type != XIT_LIST ) + XinError( 20026, XinSeverityFatal, 0L ); + rv = lm_insert_row( list->v.list->lm, row ); + return rv; +} + +int +xi_scroll( XI_OBJ * xi_obj, int nbr_lines ) +{ + return ( xi_scroll_internal( xi_obj, nbr_lines, 0, ( BOOLEAN ) ( nbr_lines < 1000 ) ) ); +} + +int +xi_scroll_percent( XI_OBJ * xi_obj, int percent ) +{ + return ( xi_scroll_internal( xi_obj, XI_SCROLL_FIRST, percent, FALSE ) ); +} + +void +xi_set_app_data( XI_OBJ * xi_obj, long app_data ) +{ + xi_obj->app_data = app_data; +} + +void +xi_set_app_data2( XI_OBJ * xi_obj, long app_data ) +{ + xi_obj->app_data2 = app_data; +} + +void +xi_set_fore_color( XI_OBJ * xi_obj, XinColor color ) +{ + XinRect rct; + + switch ( xi_obj->type ) + { + case XIT_ROW: + lm_set_color( xi_obj->parent->v.list->lm, LM_ROW, xi_obj->v.row, + 0, FALSE, color, FALSE ); + break; + case XIT_CELL: + { + LM_DATA *lmp = LMP( xi_obj->parent->v.list->lm ); + int idx = xi_obj->v.cell.row; + int idx2 = xi_obj->v.cell.column; + BOOLEAN do_redraw = ( lmp->cell_data[idx][idx2].color != color ); + + lm_set_color( xi_obj->parent->v.list->lm, LM_CELL, xi_obj->v.cell.row, + xi_obj->v.cell.column, xi_obj->v.cell.is_vert_scrolled, color, + FALSE ); + if ( do_redraw ) + { + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_get_window( xi_obj->itf ), &rct ); + } + break; + } + default: + break; + } +} + +void +xi_set_attrib( XI_OBJ * xi_obj, unsigned long attrib ) +{ + int n; + XI_OBJ **objlist; + unsigned long attrib_diff; + XinWindow win = xi_obj->itf->v.itf->xin_win; + + attrib_diff = xi_get_attrib( xi_obj ) ^ attrib; + if ( !( attrib & XI_ATR_VISIBLE ) ) + { + XI_OBJ *focus_obj, + *next_obj; + + focus_obj = xi_get_focus( xi_obj->itf ); + if ( focus_obj == xi_obj || + ( focus_obj != NULL && focus_obj->type == XIT_CELL && focus_obj->parent == xi_obj ) ) + { + if ( xi_obj->itf->v.itf->moving_focus ) + return; + next_obj = xi_find_next_obj( focus_obj, XI_NEXT_ITF_TAB, + XI_PREF_ITF_TAB_CHAR ); + if ( next_obj == focus_obj || ( focus_obj->type == XIT_CELL && focus_obj->parent == next_obj ) ) + next_obj = next_obj->itf; + xi_move_focus( next_obj ); + } + } + + switch ( xi_obj->type ) + { + case XIT_BTN: + if ( !xi_get_native_controls( xi_obj ) ) + { + XI_BTN_DATA *bd; + XinRect r; + + bd = xi_obj->v.btn; + r = bd->rct; + if ( bd->type == XIBT_TABBTN ) + r.bottom += 2; + xi_invalidate_rect( win, &r ); + } + else + { + if ( attrib_diff & XI_ATR_VISIBLE ) + { + XinWindow btn_win; + + btn_win = xi_obj->v.btn->btnctl; + XinWindowShow( btn_win, ( BOOLEAN ) ( ( attrib & XI_ATR_VISIBLE ) + != 0 ) ); + xi_invalidate_rect( win, &xi_obj->v.btn->rct ); + } + if ( attrib_diff & XI_ATR_ENABLED ) + XinWindowEnable( xi_obj->v.btn->btnctl, + ( BOOLEAN ) ( ( attrib & XI_ATR_ENABLED ) != 0 ) ); + } + xi_obj->v.btn->attrib = attrib; + break; + case XIT_FORM: + /* loop over sub-objects */ + objlist = xi_get_member_list( xi_obj, &n ); + for ( ; n > 0; n--, objlist++ ) + xi_set_attrib( *objlist, attrib ); + break; + case XIT_FIELD: + { + XinRect rct; + XI_FIELD_DATA *fd; + + stx_set_attrib( xi_obj->v.field->stx, attrib ); + fd = xi_obj->v.field; + rct = fd->rct; + if ( fd->button ) + if ( !fd->button_on_left ) + rct.right = fd->btn_rct.right; + xi_invalidate_rect( win, &rct ); + break; + } + case XIT_GROUP: + /* it is not clear how to get the proper behaviour here */ + break; + case XIT_LINE: + { + XinRect rct; + XI_LINE_DATA *ld; + + ld = xi_obj->v.line; + rct.top = min( ld->pnt1.v, ld->pnt2.v ); + rct.bottom = max( ld->pnt1.v, ld->pnt2.v ); + rct.left = min( ld->pnt1.h, ld->pnt2.h ); + rct.right = max( ld->pnt1.h, ld->pnt2.h ); + --rct.top; + rct.bottom += 3; + --rct.left; + rct.right += 3; + xi_obj->v.line->attrib = attrib; + xi_invalidate_rect( win, &rct ); + break; + } + case XIT_RECT: + xi_obj->v.rect->attrib = attrib; + xi_invalidate_rect( win, &xi_obj->v.rect->rct ); + break; + case XIT_TEXT: + xi_obj->v.text->attrib = attrib; + xi_invalidate_rect( win, &xi_obj->v.text->rct ); + break; + case XIT_ITF: + /* it is not clear how to get the proper behaviour here */ + break; + case XIT_COLUMN: + lm_set_attrib( xi_obj->parent->v.list->lm, LM_COLUMN, + xi_obj_to_idx( xi_obj ), 0, FALSE, attrib, FALSE ); + break; + case XIT_LIST: + { + XI_LIST_DATA *ld; + + ld = xi_obj->v.list; + if ( attrib & XI_ATR_VISIBLE && !ld->done_initial_xi_scroll ) + { + ld->done_initial_xi_scroll = TRUE; + xi_scroll_internal( xi_obj, XI_SCROLL_FIRST, ld->start_percent, FALSE ); + } + lm_set_attrib( ld->lm, LM_LIST, 0, 0, FALSE, attrib, FALSE ); + if ( ld->sb_win ) + { + XinWindowShow( ld->sb_win, ( BOOLEAN ) ( ( attrib & XI_ATR_VISIBLE ) != 0 ) ); + XinWindowEnable( ld->sb_win, ( BOOLEAN ) ( ( attrib & XI_ATR_ENABLED ) != 0 ) ); + } + if ( ld->hsb_win ) + { + XinWindowShow( ld->hsb_win, ( BOOLEAN ) ( ( attrib & XI_ATR_VISIBLE ) != 0 ) ); + XinWindowEnable( ld->hsb_win, ( BOOLEAN ) ( ( attrib & XI_ATR_ENABLED ) != 0 ) ); + } + break; + } + case XIT_ROW: + lm_set_attrib( xi_obj->parent->v.list->lm, LM_ROW, xi_obj->v.row, 0, FALSE, + attrib, FALSE ); + break; + case XIT_CELL: + lm_set_attrib( xi_obj->parent->v.list->lm, LM_CELL, xi_obj->v.cell.row, + xi_obj->v.cell.column, xi_obj->v.cell.is_vert_scrolled, + attrib, FALSE ); + break; + default: + XinError( 20027, XinSeverityFatal, 0L ); + break; + } +} + +void +xi_set_bufsize( XI_OBJ * xi_obj, int size ) +{ + XI_OBJ **objp; + int i; + + switch ( xi_obj->type ) + { + case XIT_FIELD: + stx_set_bufsize( xi_obj->v.field->stx, ( short ) size ); + break; + case XIT_COLUMN: + lm_set_buf_size( xi_obj->parent->v.list->lm, LM_COLUMN, + xi_obj_to_idx( xi_obj ), size ); + break; + case XIT_LIST: + case XIT_FORM: + objp = xi_obj->children; + for ( i = xi_obj->nbr_children; i > 0; i--, objp++ ) + xi_set_bufsize( *objp, size ); + break; + default: + break; + } +} + +void +xi_set_sel( XI_OBJ * xi_obj, int selstart, int selstop ) +{ + switch ( xi_obj->type ) + { + case XIT_CELL: + xi_set_focus( xi_obj ); + lm_set_sel( xi_obj->parent->v.list->lm, xi_obj->v.cell.row, + xi_obj->v.cell.column, xi_obj->v.cell.is_vert_scrolled, + selstart, selstop ); + break; + case XIT_FIELD: + xi_set_focus( xi_obj ); + stx_set_sel( xi_obj->v.field->stx, selstart, selstop ); + break; + case XIT_BTN: + case XIT_FORM: + case XIT_GROUP: + case XIT_TEXT: + case XIT_COLUMN: + case XIT_ITF: + case XIT_LIST: + case XIT_ROW: + XinError( 20028, XinSeverityFatal, 0L ); + break; + default: + break; + } +} + +void +xi_set_text( XI_OBJ * xi_obj, const char *s ) +{ + BOOLEAN ddd; + BOOLEAN do_compare = TRUE; + + if ( xi_obj == xi_obj->itf->v.itf->focus_obj ) + xi_obj->itf->v.itf->chg_flag = FALSE; + if (xi_obj->type == XIT_CELL) + { + XI_OBJ *list = xi_obj->parent; + int row = xi_obj->v.cell.row; + int column = xi_obj->v.cell.column; + LM_DATA *lmp = LMP(list->v.list->lm); + LM_CELL_DATA col_data = lmp->cell_data[row][column]; + if (!col_data.valid_data) + do_compare = FALSE; + } + if (do_compare) + { + const size_t buf_size = 256; + char *buf = (char*)XinMemoryAlloc( buf_size ); + int cmp = 0; + xi_get_text( xi_obj, buf, buf_size ); + cmp = strcmp( s, buf ); + XinMemoryFree( buf ); + if (!cmp) + return; + } + ddd = !xi_get_native_controls( xi_obj ); + switch ( xi_obj->type ) + { + case XIT_BTN: + { + XI_BTN_DATA *btn; + + btn = xi_obj->v.btn; + btn->text = ( char * ) xi_tree_realloc( btn->text, strlen( s ) + 1 ); + strcpy( btn->text, s ); + if ( ddd ) + { + if ( ( xi_get_attrib( xi_obj ) & XI_ATR_VISIBLE ) != 0 ) + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &btn->rct ); + } + else + XinWindowTitleSet( btn->btnctl, s ); + break; + } + case XIT_CELL: + lm_set_text( xi_obj->parent->v.list->lm, s, xi_obj->v.cell.row, + xi_obj->v.cell.column, xi_obj->v.cell.is_vert_scrolled ); + break; + case XIT_COLUMN: + lm_set_text( xi_obj->parent->v.list->lm, s, LM_HEADING_TEXT, + xi_obj_to_idx( xi_obj ), FALSE ); + break; + case XIT_FIELD: + { + /* XinRect rct; */ + + stx_set_text( xi_obj->v.field->stx, s ); + /* TODO change approach, simply draw text xi_get_rect(xi_obj, &rct); + * xi_invalidate_rect(xi_obj->itf->v.itf->xin_win, &rct); */ + break; + } + case XIT_ITF: + XinWindowTitleSet( xi_obj->v.itf->xin_win, s ); + break; + case XIT_ROW: + XinError( 20029, XinSeverityFatal, 0L ); + case XIT_TEXT: + { + XI_TEXT_DATA *text_data; + XinRect rct; + + text_data = xi_obj->v.text; + text_data->text = ( char * ) xi_tree_realloc( text_data->text, strlen( s ) + 1 ); + strcpy( text_data->text, s ); + if ( ( xi_get_attrib( xi_obj ) & XI_ATR_VISIBLE ) != 0 ) + { + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &rct ); + } + break; + } + case XIT_GROUP: + case XIT_FORM: + case XIT_LIST: + break; + default: + break; + } +} + +void +xi_set_override_cursor( XI_OBJ* itf, XinCursor cursor, BOOLEAN flag ) +{ + itf->v.itf->cursor_override = flag; + if ( xi_is_itf( itf ) && flag && itf->v.itf->cursor != cursor ) + { + XinWindowCursorSet( itf->v.itf->xin_win, cursor ); + itf->v.itf->cursor = cursor; + } +} + +XinColor +xi_get_underlying_color( XI_OBJ * itf, XinPoint point ) +{ + XinColor back_color = itf->v.itf->back_color; + int num, num_members; + XI_OBJ** objlist; + XI_OBJ** cur_obj; + XinRect* back_rect = NULL; + + objlist = xi_get_member_list( itf, &num_members ); + + /* Determine if the point is contained on any rectangles in the itf */ + for ( num = 0, cur_obj = objlist; num < num_members; num++, cur_obj++ ) + if ( (*cur_obj)->type == XIT_RECT ) + { + XinRect intersect; + XinRect* cur_rct = &(*cur_obj)->v.rect->rct; + if (XinRectPointContained( cur_rct, &point ) ) + { + if ( back_rect != NULL ) + { + XinRectIntersect( &intersect, back_rect, cur_rct ); + if ( intersect.top == cur_rct->top + && intersect.bottom == cur_rct->bottom + && intersect.left == cur_rct->left + && intersect.right == cur_rct->right ) + { + if ( (*cur_obj)->v.rect->back_color != 0 ) + { + back_color = (*cur_obj)->v.rect->back_color; + back_rect = &(*cur_obj)->v.rect->rct; + } + } + } + else + { + if ( (*cur_obj)->v.rect->back_color != 0 ) + { + back_color = (*cur_obj)->v.rect->back_color; + back_rect = &(*cur_obj)->v.rect->rct; + } + } + } + } + return back_color; +} + +void +xi_draw_button( XI_OBJ * xi_obj, XinRect * rct, + BOOLEAN enabled, BOOLEAN visible, BOOLEAN focus, BOOLEAN down, + BOOLEAN dflt, BOOLEAN checked, BOOLEAN box_only, BOOLEAN draw_border ) +{ + XI_BTN_DATA *bd; + XinColor fore_color; + XinColor border_color; + XinPen fore_cp; + XinWindow win; + XI_OBJ *itf; + XI_ITF_DATA *id; + int leading, + ascent, + descent; + XI_OBJ *focus_obj; + XinColor color_light = 0L; + XinColor color_ctrl = 0L; + XinColor color_dark = 0L; + + if ( !visible ) + return; + itf = xi_obj->itf; + id = itf->v.itf; + if ( id->half_baked ) + return; + win = xi_get_window( itf ); + xi_set_clip( win, NULL ); + bd = xi_obj->v.btn; + fore_color = XI_COLOR_BLACK; + if (bd->type == XIBT_BUTTON) + { + color_light = aga_get_pref(AGA_PREF_BTN_COLOR_LIGHT); + color_ctrl = aga_get_pref(AGA_PREF_BTN_COLOR_CTRL); + color_dark = aga_get_pref(AGA_PREF_BTN_COLOR_DARK); + } + fore_cp = black_cpen; + if ( bd->fore_color ) + { + fore_cp.fore_color = bd->fore_color; + fore_color = bd->fore_color; + } + switch ( bd->type ) + { + case XIBT_BUTTON: + case XIBT_BUTTON_CHECKBOX: + case XIBT_BUTTON_RADIOBTN: + { + int bline = -1; + XinRect r; + XinPen back_pen; + BOOLEAN cr_ok; + XinPoint pnt; + XinColor underlying_color; + pnt.h = rct->left; + pnt.v = rct->top; + underlying_color = xi_get_underlying_color ( itf, pnt ); + + r = *rct; + back_pen = black_cpen; + back_pen.fore_color = underlying_color; + XinWindowPenSet( win, &back_pen ); + XinWindowBrushSet( win, &hollow_cbrush ); + if ( draw_border ) + xi_draw_rect( win, &r ); + xi_inflate_rect( &r, -1 ); + xi_draw_rect( win, &r ); + r = *rct; + if ( xi_obj->v.btn->packed == TRUE ) + { + int grid_width = ( int ) xi_get_pref( XI_PREF_CONTAINER_GRID_WIDTH ); + xi_inflate_rect( &r, -grid_width ); + } + else + { + XI_BTN_TYPE bt; + + bt = xi_obj->v.btn->type; + if ( bt == XIBT_BUTTON || bt == XIBT_BUTTON_CHECKBOX || + bt == XIBT_BUTTON_RADIOBTN ) + xi_inflate_rect( &r, -1 ); // Was -3 + } + XinWindowDrawModeSet( win, XinDrawModeCopy ); + + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_3D_LOOK ) ) + xi_draw_shaded_rect( win, &r, ( BOOLEAN ) ( down || bd->checked ), 2, color_light, color_ctrl, color_dark ); + else + xi_draw_3d_rect( win, &r, ( BOOLEAN ) ( down || bd->checked ), 2, color_light, color_ctrl, color_dark ); + + if ( bd->up_icon_rid ) + { + int x, + y; + XinRect r2; + + x = r.left + 2 + bd->icon_x; + y = r.top + 2 + bd->icon_y; + r2 = r; + xi_inflate_rect( &r2, -2 ); + xi_set_clip( win, &r2 ); + if ( down || bd->checked) // Guy added bd->checked + xi_draw_icon( win, x, y + 1, bd->down_icon_rid, XI_COLOR_BLACK, + color_ctrl ); + else + { + if ( enabled || !bd->disabled_icon_rid ) + xi_draw_icon( win, x, y, bd->up_icon_rid, XI_COLOR_BLACK, + color_ctrl ); + else + xi_draw_icon( win, x, y, bd->disabled_icon_rid, XI_COLOR_BLACK, + color_ctrl ); + } + xi_set_clip( win, NULL ); + } + else if ( bd->up_bitmap != NULL ) + { + XinRect r2; + + r2 = r; + xi_inflate_rect( &r2, -2 ); + if ( down ) + xi_bitmap_draw( bd->down_bitmap, win, &r2, &r2, FALSE ); + else if ( enabled || bd->disabled_bitmap == NULL ) + xi_bitmap_draw( bd->up_bitmap, win, &r2, &r2, FALSE ); + else + xi_bitmap_draw( bd->disabled_bitmap, win, &r2, &r2, FALSE ); + xi_set_clip( win, NULL ); + } + else + { + unsigned long attrib; + XinRect text_rect; + // XinColor color; + XinFont *fontp; + + attrib = XI_ATR_VCENTER | XI_ATR_HCENTER | XI_ATR_VISIBLE; + if ( enabled ) + XinWindowColorTextForeSet( win, fore_color ); + else + XinWindowColorTextForeSet( win, + ( XinColor ) xi_get_pref( XI_PREF_COLOR_DISABLED ) ); + text_rect = r; + if ( down ) + { + text_rect.top += 2; + text_rect.left += 2; + } + fontp = xi_obj->v.btn->font; + if ( fontp == NULL ) + fontp = xi_obj->itf->v.itf->font; + if ( fontp == NULL ) + fontp = xi_get_system_font( ); + XinWindowColorTextBackSet( win, color_ctrl ); + XinWindowTextOpaqueSet( win, FALSE ); + XinWindowFontMap( win, fontp ); + XinFontMetricsGet( fontp, &leading, &ascent, &descent ); + xi_draw_clipped_text( win, fontp, bd->text, &text_rect, &text_rect, attrib, FALSE, 0, -1, + bd->mnemonic, bd->mnemonic_instance, &bline ); + } + + /* draw the solid line around the button that shows that it will be + * pressed if the user presses cr */ + focus_obj = xi_get_focus( itf ); + cr_ok = FALSE; + if ( focus_obj && focus_obj->type != XIT_BTN && !xi_cr_is_ok( focus_obj ) ) + cr_ok = TRUE; + if ( ( dflt && cr_ok ) || focus ) + border_color = XI_COLOR_BLACK; + else + border_color = underlying_color; + if ( draw_border ) + { + XinRect rct2; + XinPen pen; + + rct2 = r; + xi_inflate_rect( &rct2, 1 ); + pen.width = 1; + pen.fore_color = border_color; + pen.pattern = XinPenSolid; + XinWindowPenSet( win, &pen ); + XinWindowBrushSet( win, &hollow_cbrush ); + xi_draw_rect( win, &rct2 ); + } + + /* draw the dashed line inside the button that shows focus */ + if ( focus && bd->up_icon_rid == 0 && bd->up_bitmap == NULL ) + { + XinRect rct2; +/* + int middle; + int font_height; + int font_top; +*/ + XinPen pen; + + rct2 = r; + xi_inflate_rect( &rct2, -3 ); +/* middle = ( rct2.top + rct2.bottom ) / 2; + font_height = ascent + descent + leading; + font_top = middle - font_height / 2; + rct2.top = middle - font_height / 2 - 3; + rct2.bottom = font_top + font_height + 2; + if ( bline != -1 ) + rct2.bottom = bline + descent + 2; + rct2.top = max( rct2.top, r.top + 3 ); + rct2.bottom = min( rct2.bottom, r.bottom ); */ + pen.width = 1; + pen.fore_color = XI_COLOR_BLACK; + pen.pattern = XinPenSolid; + XinWindowPenSet( win, &pen ); + XinWindowBrushSet( win, &hollow_cbrush ); + xi_draw_dotted_rect( win, &rct2 ); + } + break; + } + case XIBT_RADIOBTN: + { + XinRect rbrct, + rct2; + unsigned long attrib; + XinRect text_rect; + XinColor color; + + rbrct = *rct; + rbrct.bottom -= 4; + rct2 = rbrct; + rct2.right = rct2.left + ( rct2.bottom - rct2.top ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + XinWindowPenSet( win, &hollow_cpen ); + if ( id->back_color && !box_only ) + { + XinWindowBrushSet( win, &hollow_cbrush ); + xi_draw_rect( win, rct ); + } + xi_draw_3d_diamond( win, &rct2, checked, down, down ? 2 : 1, + down ? bd->fore_color : 0L ); + if ( checked ) + { + XinRect rct; + + rct = rct2; + rct.top += 4; + rct.left += 4; + rct.bottom -= 4; + rct.right -= 4; + xi_draw_3d_diamond( win, &rct, FALSE, TRUE, rct.right - rct.left, + enabled ? bd->fore_color : xi_get_pref( XI_PREF_COLOR_DISABLED ) ); + } + if ( !box_only ) + { + XinPen cpen; + XinFont *fontp; + + attrib = XI_ATR_VCENTER | XI_ATR_VISIBLE; + if ( enabled ) + XinWindowColorTextForeSet( win, fore_color ); + else + XinWindowColorTextForeSet( win, + ( XinColor ) xi_get_pref( XI_PREF_COLOR_DISABLED ) ); + text_rect = *rct; + text_rect.left = rct2.right + ( rct2.right - rct2.left ) / 2; + fontp = xi_obj->v.btn->font; + if ( fontp == NULL ) + fontp = xi_obj->itf->v.itf->font; + if ( fontp == NULL ) + fontp = xi_get_system_font( ); + color = ( XinColor ) xi_get_pref( XI_PREF_COLOR_CTRL ); + XinWindowColorTextBackSet( win, color ); + XinWindowTextOpaqueSet( win, FALSE ); + XinWindowFontMap( win, fontp ); + xi_draw_clipped_text( win, fontp, bd->text, &text_rect, &text_rect, attrib, FALSE, 0, -1, + bd->mnemonic, bd->mnemonic_instance, NULL ); + if ( focus ) + { + cpen = black_cpen; + cpen.pattern = XinPenSolid; + XinWindowPenSet( win, &cpen ); + XinWindowBrushSet( win, &hollow_cbrush ); + text_rect.left = rct2.right + ( rct2.right - rct2.left ) / 4; + xi_draw_dotted_rect( win, &text_rect ); + } + else + { +/* + if ( id->back_color ) + { + cpen = black_cpen; + cpen.fore_color = id->back_color; + XinWindowPenSet( win, &cpen ); + XinWindowBrushSet( win, &hollow_cbrush ); + text_rect.left = rct2.right + ( rct2.right - rct2.left ) / 4; + xi_draw_rect( win, &text_rect ); + } +*/ + } + } + break; + } + case XIBT_TABBTN: + { + XinRect tab_rect, + rect; + XinBrush back_brush; + XinPen highlight_pen; + XinPen shadow_pen; + BOOLEAN checked_is_to_right; + BOOLEAN checked_is_to_left; + int index, + baseline; + XinFont *fontp; + unsigned long attrib; + + back_brush.pattern = XinBrushSolid; + back_brush.fore_color = ( XinColor ) xi_get_pref( XI_PREF_COLOR_CTRL ); + XinWindowBrushSet( win, &back_brush ); + xi_set_clip( win, NULL ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + XinWindowPenSet( win, &hollow_cpen ); + highlight_pen = black_cpen; + highlight_pen.fore_color = xi_get_pref( XI_PREF_COLOR_LIGHT ); + shadow_pen = black_cpen; + shadow_pen.fore_color = xi_get_pref( XI_PREF_COLOR_DARK ); + + index = xi_obj_to_idx( xi_obj ); + if ( index < xi_obj->parent->nbr_children - 1 ) + checked_is_to_right = xi_obj->parent->children[index + 1]->v.btn->checked; + else + checked_is_to_right = FALSE; + if ( index > 0 ) + checked_is_to_left = xi_obj->parent->children[index - 1]->v.btn->checked; + else + checked_is_to_left = FALSE; + tab_rect = *rct; + ++tab_rect.bottom; + if ( xi_obj->v.btn->checked ) + { + XinPoint p1, + p2; + + { + XinRect temp = tab_rect; + + temp.top++; + temp.left++; + xi_draw_rect( win, &temp ); + } + + XinWindowPenSet( win, &highlight_pen ); + /* left line */ + p1.h = tab_rect.left; + p1.v = tab_rect.bottom - 1; + xi_move_to( win, p1 ); + p2.h = tab_rect.left; + p2.v = tab_rect.top + 2; + xi_draw_line( win, p2 ); + + /* diagonal line from left edge to top */ + p1.h = tab_rect.left; + p1.v = tab_rect.top + 3; + xi_move_to( win, p1 ); + p2.h = tab_rect.left + 3; + p2.v = tab_rect.top; + xi_draw_line( win, p2 ); + + /* top line */ + p1.h = tab_rect.left + 2; + p1.v = tab_rect.top; + xi_move_to( win, p1 ); + p2.h = tab_rect.right - 2; + p2.v = tab_rect.top; + xi_draw_line( win, p2 ); + + /* shadow and black lines on right */ + XinWindowPenSet( win, &shadow_pen ); + p1.h = tab_rect.right - 2; + p1.v = tab_rect.top; + xi_move_to( win, p1 ); + p2.h = tab_rect.right - 2; + p2.v = tab_rect.bottom; + xi_draw_line( win, p2 ); + + XinWindowPenSet( win, &black_cpen ); + p1.h = tab_rect.right - 1; + p1.v = tab_rect.top + 1; + xi_move_to( win, p1 ); + p2.h = tab_rect.right - 1; + p2.v = tab_rect.bottom; + xi_draw_line( win, p2 ); + } + else + { + XinPoint p1, + p2; + + { + XinRect temp = tab_rect; + + temp.top += 4; + if ( !checked_is_to_left ) + temp.left++; + xi_draw_rect( win, &temp ); + } + + XinWindowPenSet( win, &highlight_pen ); + /* draw line on left edge of tab */ + if ( !checked_is_to_left ) + { + p1.h = tab_rect.left; + p1.v = tab_rect.bottom - 2; + xi_move_to( win, p1 ); + p2.h = tab_rect.left; + p2.v = tab_rect.top + 4; + xi_draw_line( win, p2 ); + } + + /* diagonal line from left edge to top */ + if ( checked_is_to_left ) + { + p1.h = tab_rect.left; + p1.v = tab_rect.top + 5; + xi_move_to( win, p1 ); + p2.h = tab_rect.left + 2; + p2.v = tab_rect.top + 3; + xi_draw_line( win, p2 ); + } + else + { + p1.h = tab_rect.left; + p1.v = tab_rect.top + 6; + xi_move_to( win, p1 ); + p2.h = tab_rect.left + 3; + p2.v = tab_rect.top + 3; + xi_draw_line( win, p2 ); + } + + /* top line */ + p1.h = tab_rect.left + 2; + p1.v = tab_rect.top + 3; + xi_move_to( win, p1 ); + p2.h = tab_rect.right - 2; + p2.v = tab_rect.top + 3; + xi_draw_line( win, p2 ); + + /* shadow line on right */ + XinWindowPenSet( win, &shadow_pen ); + p1.h = tab_rect.right - 2; + p1.v = tab_rect.top + 3; + xi_move_to( win, p1 ); + p2.h = tab_rect.right - 2; + p2.v = tab_rect.bottom - 2; + xi_draw_line( win, p2 ); + + /* black line on right */ + if ( !checked_is_to_right ) + { + XinWindowPenSet( win, &black_cpen ); + p1.h = tab_rect.right - 1; + p1.v = tab_rect.top + 4; + xi_move_to( win, p1 ); + p2.h = tab_rect.right - 1; + p2.v = tab_rect.bottom - 2; + xi_draw_line( win, p2 ); + } + + XinWindowPenSet( win, &highlight_pen ); + p1.h = tab_rect.left; + p1.v = tab_rect.bottom - 1; + xi_move_to( win, p1 ); + p2.h = tab_rect.right; + p2.v = tab_rect.bottom - 1; + xi_draw_line( win, p2 ); + } + fontp = xi_obj->v.btn->font; + if ( !fontp ) + fontp = xi_obj->itf->v.itf->font; + if ( !fontp ) + fontp = xi_get_system_font( ); + if ( checked ) + { + XinFont *font; + + XinFontCopy( &font, fontp ); + XinFontBoldSet( font, TRUE ); + fontp = font; + } + XinWindowFontMap( win, fontp ); + XinFontMetricsGet( fontp, &leading, &ascent, &descent ); + attrib = XI_ATR_HCENTER | XI_ATR_VCENTER | XI_ATR_VISIBLE; + rect = tab_rect; + ++rect.left; + rect.right -= 2; + rect.top += 3; + if ( enabled ) + XinWindowColorTextForeSet( win, fore_cp.fore_color ); + else + XinWindowColorTextForeSet( win, ( XinColor ) xi_get_pref( XI_PREF_COLOR_DISABLED ) ); + XinWindowTextOpaqueSet( win, FALSE ); + xi_draw_clipped_text( win, fontp, bd->text, &rect, &rect, attrib, FALSE, 0, -1, + bd->mnemonic, bd->mnemonic_instance, NULL ); +#if XIWS == XIWS_WM + NOREF( rule_and_space ); + baseline = rect.top + 8; +#else + baseline = rect.top + leading + ascent + + ( rect.bottom - rect.top - leading - ascent - descent ) / 2 - 1; +#endif + if ( focus ) + { + rect.top = baseline - leading - ascent; + rect.bottom = baseline + descent - 1; + ++rect.left; + --rect.right; + XinWindowPenSet( win, &black_cpen ); + xi_draw_dotted_rect( win, &rect ); + } + break; + } + case XIBT_CHECKBOX: + { + XinRect cbrct, + rct2; + unsigned long attrib; + XinRect text_rect; + XinColor color; + + cbrct = *rct; + cbrct.bottom -= 4; + rct2 = cbrct; + rct2.right = rct2.left + ( rct2.bottom - rct2.top ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + XinWindowPenSet( win, &hollow_cpen ); + if ( id->back_color && !box_only ) + { + XinWindowBrushSet( win, &hollow_cbrush ); + xi_draw_rect( win, rct ); + } + if ( down ) + { + XinWindowPenSet( win, &fore_cp ); + XinWindowBrushSet( win, &hollow_cbrush ); + xi_draw_thick_rect( win, &rct2, 2 ); + } + else + { + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_3D_LOOK ) ) + xi_draw_shaded_rect( win, &rct2, down, 1, 0L, 0L, 0L ); + else + xi_draw_3d_rect( win, &rct2, down, 1, 0L, 0L, 0L ); + } + if ( !enabled ) + fore_cp.fore_color = xi_get_pref( XI_PREF_COLOR_DISABLED ); + if ( checked ) + { + XinPoint pnt1, + pnt2; + + XinWindowPenSet( win, &fore_cp ); + pnt1.h = rct2.left + 2; + pnt1.v = rct2.bottom - 7; + xi_move_to( win, pnt1 ); + pnt2.h = pnt1.h; + pnt2.v = pnt1.v + 5; + xi_draw_line( win, pnt2 ); + + pnt1.h++; + pnt1.v--; + xi_move_to( win, pnt1 ); + pnt2.h++; + xi_draw_line( win, pnt2 ); + + pnt1.h++; + pnt1.v = rct2.bottom - 5; + pnt2 = pnt1; + pnt2.v += 2; + + while ( pnt1.v >= ( rct2.top + 3 ) && pnt1.h <= ( rct2.right - 4 ) ) + { + xi_move_to( win, pnt1 ); + xi_draw_line( win, pnt2 ); + pnt1.h++; + pnt1.v--; + pnt2.h++; + pnt2.v--; + } + pnt1.v++; + xi_move_to( win, pnt1 ); + xi_draw_line( win, pnt2 ); + + /* Sarebbe bello ma ... non è trasparente + XinRect rct3 = rct2; + xi_inflate_rect(&rct3, -2); + xi_draw_checkmark(win, &rct3); + */ + } + if ( !box_only ) + { + XinFont *fontp; + + attrib = XI_ATR_VCENTER | XI_ATR_VISIBLE; + if ( enabled ) + XinWindowColorTextForeSet( win, fore_color ); + else + XinWindowColorTextForeSet( win, + ( XinColor ) xi_get_pref( XI_PREF_COLOR_DISABLED ) ); + text_rect = *rct; + text_rect.left = rct2.right + ( rct2.right - rct2.left ) / 2; + fontp = xi_obj->v.btn->font; + if ( !fontp ) + fontp = xi_obj->itf->v.itf->font; + if ( fontp == NULL ) + fontp = xi_get_system_font( ); + color = ( XinColor ) xi_get_pref( XI_PREF_COLOR_CTRL ); + XinWindowColorTextBackSet( win, color ); + XinWindowTextOpaqueSet( win, FALSE ); + XinWindowFontMap( win, fontp ); + xi_draw_clipped_text( win, fontp, bd->text, &text_rect, &text_rect, attrib, FALSE, 0, -1, + bd->mnemonic, bd->mnemonic_instance, NULL ); + xi_set_clip( win, NULL ); + if ( focus ) + { + XinPen cpen; + + cpen = black_cpen; + XinWindowPenSet( win, &cpen ); + XinWindowBrushSet( win, &hollow_cbrush ); + text_rect.left = rct2.right + ( rct2.right - rct2.left ) / 4; + xi_draw_dotted_rect( win, &text_rect ); + } + else + { +/* + if ( id->back_color ) + { + XinPen cpen; + + cpen = black_cpen; + cpen.fore_color = id->back_color; + XinWindowPenSet( win, &cpen ); + XinWindowBrushSet( win, &hollow_cbrush ); + text_rect.left = rct2.right + ( rct2.right - rct2.left ) / 4; + xi_draw_rect( win, &text_rect ); + } +*/ + } + } + break; + } + } +} + + +/* -------------------------------------------------------------------------*/ +/* xi_set_fixed_columns */ +/* -------------------------------------------------------------------------*/ + +void +xi_set_fixed_columns( XI_OBJ * list, int new_fixed_count ) +{ + if ( list->type != XIT_LIST ) + XinError( 20031, XinSeverityFatal, 0L ); + lm_set_fixed_columns( list->v.list->lm, new_fixed_count ); +} + +/* -------------------------------------------------------------------------*/ +/* xi_get_fixed_columns */ +/* -------------------------------------------------------------------------*/ +int +xi_get_fixed_columns( XI_OBJ * list ) +{ + if ( list->type != XIT_LIST ) + XinError( 20038, XinSeverityFatal, 0L ); + return lm_get_fixed_columns( list->v.list->lm ); +} + +/* -------------------------------------------------------------------------*/ +/* xi_get_handle */ +/* -------------------------------------------------------------------------*/ +long +xi_get_handle( XI_OBJ * list, XI_OBJ * child ) +{ + LM_DATA *lm_data; + + if ( list->type != XIT_LIST ) + return -1L; + lm_data = ( LM_DATA * ) list->v.list->lm; + switch ( child->type ) + { + case XIT_ROW: + { + int row = child->v.row; + + if ( child->v.row_data.is_vert_scrolled ) + return lm_focus_rec_get( lm_data ); + if ( row >= 0 && row < lm_data->nbr_realized_rows ) + return lm_data->recs[row]; + break; + } + case XIT_CELL: + { + int row; + + if ( child->v.cell.is_vert_scrolled ) + return lm_focus_rec_get( lm_data ); + row = child->v.cell.row; + if ( row >= 0 && row < lm_data->nbr_realized_rows ) + return lm_data->recs[row]; + break; + } + default: + break; + } + return -1L; +} + +/* -------------------------------------------------------------------------*/ +/* xi_field_calc_height_font */ +/* -------------------------------------------------------------------------*/ +int +xi_field_calc_height_font( XinFont * font ) +{ + if ( font == 0 ) + font = xi_get_system_font( ); + return xi_get_fu_height_font( font ); +} + +/* -------------------------------------------------------------------------*/ +/* xi_button_calc_height_font */ +/* -------------------------------------------------------------------------*/ +int +xi_button_calc_height_font( XinFont * font ) +{ + return xi_field_calc_height_font( font ); +} + +/* -------------------------------------------------------------------------*/ +/* xi_field_calc_width_font */ +/* -------------------------------------------------------------------------*/ +int +xi_field_calc_width_font( XinFont * font, char *string ) +{ + int result; + XinWindow win; + XinRect rct = {-1000, -1000, -900, -900}; + XinFont *calc_font; + + if ( font ) + calc_font = font; + else + calc_font = xi_get_system_font( ); + { + XinWindowDef Def; + + MEMCLEAR( Def ); + Def.type = XinWindowTypeDocument; + Def.border_style = XinBorderFixed; + Def.p_rect = &rct; + Def.title = ""; + win = XinWindowCreate( &Def ); + } + + XinWindowFontMap( win, calc_font ); + result = XinFontTextWidthGet( calc_font, string, -1 ) + 4; + XinFontUnmap( calc_font ); /* RGM: Unmap hack */ + XinWindowDestroy( win ); + return result; +} + +/* -------------------------------------------------------------------------*/ +/* xi_list_def_get_rows */ +/* -------------------------------------------------------------------------*/ +int +xi_list_def_get_rows( XI_OBJ_DEF * list_def ) +{ + int pix_row_spacing, + height, + pix_row1_top, + title_height; + + if ( list_def->v.list->one_row_list ) + return 1; + lm_get_vertical_metrics( list_def, &pix_row1_top, &pix_row_spacing, &height, + &title_height ); + return height / pix_row_spacing; +} + +/* -------------------------------------------------------------------------*/ +/* xi_list_def_get_height */ +/* -------------------------------------------------------------------------*/ +int +xi_list_def_get_client_height( XI_OBJ_DEF * list_def, int rows ) +{ + int pix_row_spacing, + height, + pix_row1_top, + title_height; + + lm_get_vertical_metrics( list_def, &pix_row1_top, &pix_row_spacing, &height, + &title_height ); + return title_height + rows * pix_row_spacing + ( BORDER_WIDTH - RULE_WIDTH_H ); +} + +/* -------------------------------------------------------------------------*/ +/* xi_list_def_get_height */ +/* -------------------------------------------------------------------------*/ +int +xi_list_def_get_outer_height( XI_OBJ_DEF * list_def, int rows ) +{ + int result; + + result = xi_list_def_get_client_height( list_def, rows ); + return result + ( int ) xi_get_pref( XI_PREF_SB_HEIGHT ); +} + +/* -------------------------------------------------------------------------*/ +/* button_get_horz_padding */ +/* -------------------------------------------------------------------------*/ +static int +button_get_horz_padding( int type, int height, BOOLEAN packed ) +{ + switch ( type ) + { +case XIBT_BUTTON: +case XIBT_BUTTON_CHECKBOX: +case XIBT_BUTTON_RADIOBTN: + if ( packed ) + return ( int ) xi_get_pref( XI_PREF_CONTAINER_GRID_WIDTH ) * 2; + return 6; + case XIBT_RADIOBTN: + return height + height / 2 - 6; + case XIBT_TABBTN: + return height + 4; + case XIBT_CHECKBOX: + return height + height / 2 - 6; + } + return 0; +} + +/* -------------------------------------------------------------------------*/ +/* xi_button_calc_height */ +/* -------------------------------------------------------------------------*/ +int +xi_button_calc_pixel_height( int height ) +{ + return height + 6; +} + +/* -------------------------------------------------------------------------*/ +/* xi_button_calc_height */ +/* -------------------------------------------------------------------------*/ +int +xi_button_calc_pixel_width( int width ) +{ + return width + 6; +} + +/* -------------------------------------------------------------------------*/ +/* xi_button_def_get_width */ +/* -------------------------------------------------------------------------*/ + +int +xi_button_def_get_width( XI_OBJ_DEF * obj_def ) +{ + XinFont *font; + XinRect rct = {-1000, -1000, -900, -900}; + XinWindow win; + int width; + XI_BTN_DEF *button; + + if ( obj_def->type != XIT_BTN ) + return 0; + font = xi_def_get_font( obj_def ); + { + XinWindowDef Def; + + MEMCLEAR( Def ); + Def.type = XinWindowTypeDocument; + Def.border_style = XinBorderFixed; + Def.p_rect = &rct; + Def.title = ""; + win = XinWindowCreate( &Def ); + } + XinWindowFontMap( win, font ); + button = obj_def->v.btn; + width = XinFontTextWidthGet( font, button->text, -1 ); + width += button_get_horz_padding( button->type, xi_get_fu_height_font( font ), + FALSE ); + XinFontDestroy( font ); + XinWindowDestroy( win ); + return width; +} + +/* -------------------------------------------------------------------------*/ +/* xi_container_def_get_btn_width */ +/* -------------------------------------------------------------------------*/ + +int +xi_container_def_get_btn_width( XI_OBJ_DEF * obj_def ) +{ + int i; + XinFont *font; + XinRect rct = {-1000, -1000, -900, -900}; + XinWindow win; + int max_width; + XI_CONTAINER_DEF *container; + BOOLEAN packed; + + if ( obj_def->type != XIT_CONTAINER || obj_def->nbr_children <= 0 ) + return 0; + font = xi_def_get_font( obj_def ); + max_width = 0; + { + XinWindowDef Def; + + MEMCLEAR( Def ); + Def.type = XinWindowTypeDocument; + Def.border_style = XinBorderFixed; + Def.p_rect = &rct; + Def.title = ""; + win = XinWindowCreate( &Def ); + } + XinWindowFontMap( win, font ); + for ( i = 0; i < obj_def->nbr_children; ++i ) + { + XI_BTN_DEF *button; + int width; + + button = obj_def->children[i]->v.btn; + width = XinFontTextWidthGet( font, button->text, -1 ); + max_width = max( width, max_width ); + } + container = obj_def->v.container; + packed = ( ( container->orientation == XI_GRID_HORIZONTAL + || container->orientation == XI_GRID_VERTICAL ) + && container->packed ); + max_width += button_get_horz_padding( obj_def->children[0]->v.btn->type, + xi_get_fu_height_font( font ), + packed ); + XinFontDestroy( font ); + XinWindowDestroy( win ); + return max_width; +} + +/* -------------------------------------------------------------------------*/ +/* xi_container_def_get_width */ +/* -------------------------------------------------------------------------*/ + +int +xi_container_def_get_width( XI_OBJ_DEF * obj_def ) +{ + XI_CONTAINER_DEF *container; + + container = obj_def->v.container; + switch ( container->orientation ) + { + case XI_STACK_HORIZONTAL: + { + int horz_spacing; + + if ( container->packed ) + horz_spacing = 0; + else if ( ( horz_spacing = ( int ) xi_get_pref( XI_PREF_HORZ_PIXEL_SPACING ) ) + == 0 ) + { + XinFont *font; + + font = xi_def_get_font( obj_def ); + horz_spacing = ( short ) ( ( xi_get_pref( XI_PREF_HORZ_SPACING ) + * xi_get_fu_width_font( font ) ) / XI_FU_MULTIPLE ); + XinFontDestroy( font ); + } + return xi_container_def_get_btn_width( obj_def ) * obj_def->nbr_children + + ( obj_def->nbr_children - 1 ) * horz_spacing; + } + case XI_STACK_VERTICAL: + return xi_container_def_get_btn_width( obj_def ); + default: + break; + } + return 0; +} + +/* -------------------------------------------------------------------------*/ +/* xi_container_def_get_height */ +/* -------------------------------------------------------------------------*/ + +int +xi_container_def_get_height( XI_OBJ_DEF * obj_def ) +{ + XI_CONTAINER_DEF *container; + XinFont *font; + int height; + int vert_spacing; + int top_offset; + + if ( obj_def->nbr_children == 0 ) + return 0; + container = obj_def->v.container; + font = xi_def_get_font( obj_def ); + height = xi_button_calc_height_font( font ); + XinFontDestroy( font ); + if ( container->orientation == XI_STACK_HORIZONTAL ) + return height; + if ( container->orientation != XI_STACK_VERTICAL ) + return 0; + switch ( obj_def->children[0]->v.btn->type ) + { + case XIBT_BUTTON: + case XIBT_BUTTON_CHECKBOX: + case XIBT_BUTTON_RADIOBTN: + case XIBT_TABBTN: + if ( container->packed ) + vert_spacing = 0; + else if ( ( vert_spacing = ( int ) xi_get_pref( XI_PREF_VERT_PIXEL_SPACING ) ) + == 0 ) + vert_spacing = ( int ) ( ( xi_get_pref( XI_PREF_VERT_SPACING ) + * height ) / XI_FU_MULTIPLE ); + top_offset = vert_spacing / 2; + break; + case XIBT_CHECKBOX: + case XIBT_RADIOBTN: + vert_spacing = 0; + top_offset = 0; + break; + default: + vert_spacing = 0; + top_offset = 0; + break; + } + return height * obj_def->nbr_children + vert_spacing + * ( obj_def->nbr_children - 1 ) + top_offset; +} + + +void +xi_force_focus_cell_visible( XI_OBJ * list ) +{ + int row, + column; + BOOLEAN v_scrolled; + LM_FOCUS_CELL_VISIBLE_FORCE_ARGS args; + LM_DATA *lmp = ( LM_DATA * ) list->v.list->lm; + + lm_focus_cell_get( lmp, &row, &column, &v_scrolled ); + MEMCLEAR( args ); + args.lmp = ( LM_DATA * ) list->v.list->lm; + args.row = row; + args.column = column; + args.vert_scrolled = v_scrolled; + lm_focus_cell_visible_force( &args ); +} + +BOOLEAN +xi_cell_data_valid( XI_OBJ * cell ) +{ + XI_OBJ * list = cell->parent; + LM_DATA *lmp = ( LM_DATA * ) list->v.list->lm; + + if (lmp->nbr_realized_rows <= cell->v.cell.row || + lmp->nbr_columns <= cell->v.cell.column) + return FALSE; + return lmp->cell_data[cell->v.cell.row][cell->v.cell.column].valid_data; +} diff --git a/src/xi01/xi.h b/src/xi01/xi.h new file mode 100644 index 000000000..798a600b2 --- /dev/null +++ b/src/xi01/xi.h @@ -0,0 +1,1534 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#ifndef INCL_XI +#define INCL_XI + +#ifndef XI_R4_API + +#define OLDXVT_H +#ifndef XVT_INCL_XVT +#include "xvt.h" +#endif + +#endif + +#ifdef WIN32 +#if XIAGADLL == 1 + #define XIDLL __declspec(dllexport) +#else + #define XIDLL __declspec(dllimport) +#endif +#else +#define XIDLL +#endif + + +#include "xiport.h" + +#define XI_VERSION "4.0" +#define XI_VERSION_NBR 4.0 + +#define MEMCLEAR( x ) memset(( char* )&( x ), '\0', ( size_t )sizeof( x )) + +/* FORM UNITS */ +#define XI_FU_MULTIPLE 8 + +/* character modifier constants */ +#define XI_MOD_SHIFT 0x10000000L +#define XI_MOD_CONTROL 0x20000000L +#define XI_MOD_ALT 0x40000000L /* not yet supported */ + +#define HSCROLL_CID_CONST 6000 + +#ifndef XI_R4_API +typedef XinRect XI_RCT; +typedef XinPoint XI_PNT; +#if XVT_CC != XVT_CC_MACCW +#define XinWindow WINDOW +#endif +#endif + +typedef enum _e_search_type +{ + XI_SEARCH_FOR_FOCUSABLE, + XI_SEARCH_FOR_FIELD, + XI_SEARCH_FOR_TAB_CID, + XI_SEARCH_FOR_INITIAL +} + +XI_SEARCH_TYPE; + +typedef enum _e_next_type +{ + XI_NEXT_FORM_TAB, + XI_NEXT_FORM_BACKTAB, + XI_NEXT_ITF_TAB, + XI_NEXT_ITF_BACKTAB +} + +XI_NEXT_TYPE; + +typedef enum _e_dequeue_flag +{ + XI_DEQUEUE_INIT, + XI_DEQUEUE_COMPLETE, + XI_DEQUEUE_CALL +} + +XI_DEQUEUE_FLAG; + +typedef long LM; +typedef long STX; + +#define XI_ATR_ENABLED 0x1L +#define XI_ATR_EDITMENU 0x2L +#define XI_ATR_AUTOSELECT 0x4L +#define XI_ATR_AUTOSCROLL 0x8L +#define XI_ATR_RJUST 0x10L +#define XI_ATR_BORDER 0x20L +#define XI_ATR_VISIBLE 0x40L +#define XI_ATR_FOCUSBORDER 0x80L +#define XI_ATR_READONLY 0x100L +#define XI_ATR_NAVIGATE 0x200L +#define XI_ATR_TABWRAP 0x400L +#define XI_ATR_PASSWORD 0x800L +#define XI_ATR_SELECTED 0x1000L +#define XI_ATR_VCENTER 0x2000L +#define XI_ATR_SELECTABLE 0x4000L +#define XI_ATR_COL_SELECTABLE 0x8000L +#define XI_ATR_HCENTER 0x10000L +#define XI_AGA_ATR_AUTOEND 0x20000L + +#define XI_MAX_EVENT 100 +#define XI_NULL_OBJ (( XI_OBJ* ) NULL ) +#define XI_SCROLL_PGUP 1001 +#define XI_SCROLL_PGDOWN 1002 +#define XI_SCROLL_FIRST 1003 +#define XI_SCROLL_LAST 1004 + +#ifdef __cplusplus +extern "C" +{ +#endif + extern BOOLEAN xi_false; +#ifdef __cplusplus +} + +#endif + +typedef struct +{ + short row; + short column; +} XI_CELL_SPEC; + +typedef enum +{ + XIC_ENABLED, + XIC_BACK, + XIC_HILIGHT, + XIC_SHADOW, + XIC_ACTIVE, + XIC_DISABLED, + XIC_DISABLED_BACK, + XIC_WHITE_SPACE, + XIC_ACTIVE_BACK, + XIC_FORE +} + XI_COLOR_PART; + +struct _xi_obj; +struct _xi_event; + +#ifdef __cplusplus +extern "C" +{ +#endif + typedef void ( *XI_EVENT_HANDLER ) ( struct _xi_obj * itf, struct _xi_event * xiev ); +#ifdef __cplusplus +} + +#endif + +/********************************** +* XI Preferences enumeration +**********************************/ +typedef enum +{ + XI_PREF_OVERLAP, + XI_PREF_FORM_TAB_CHAR, + XI_PREF_FORM_BACKTAB_CHAR, + XI_PREF_SCROLL_INC, + XI_PREF_3D_LOOK, + XI_PREF_USE_APP_DATA, + XI_PREF_AUTOSEL_ON_MOUSE, + XI_PREF_CELL_BTN_ICON_X, + XI_PREF_CELL_BTN_ICON_Y, + XI_PREF_R4_API, + XI_PREF_PASSWORD_CHAR, + XI_PREF_USE_TX_SUPPORT, + XI_PREF_SINGLE_CLICK_COL_SELECT, /* Only when columns are also movable */ + XI_PREF_COLUMN_OFFSET, + XI_PREF_SB_OFFSET, + XI_PREF_SB_WIDTH, + XI_PREF_SB_HEIGHT, + XI_PREF_SIZE_CURSOR_RID, + XI_PREF_HAND_CURSOR_RID, + XI_PREF_VSIZE_CURSOR_RID, + XI_PREF_COMBO_ICON, + XI_PREF_COLOR_LIGHT, + XI_PREF_COLOR_CTRL, + XI_PREF_COLOR_DARK, + XI_PREF_OPTIMIZE_CELL_REQUESTS, + XI_PREF_CARET_WIDTH, + XI_PREF_TRIPLE_CLICK_TIME, + XI_PREF_BUTTON_KEY, + XI_PREF_LIMIT_MIN_WIN_SIZE, + XI_PREF_DEFAULT_MAX_LINES_IN_CELL, + XI_PREF_KEEP_FOCUS_FIXED, + XI_PREF_NATIVE_CTRLS, + XI_PREF_ITF_TAB_CHAR, + XI_PREF_ITF_BACKTAB_CHAR, + XI_PREF_ITF_WS_RIGHT, /* in form units */ + XI_PREF_ITF_WS_BOTTOM, /* in form units */ + XI_PREF_VIR_SP_H, + XI_PREF_VIR_SP_V, + XI_PREF_DBL_PRESSES_BUTTON, + XI_PREF_CONTAINER_GRID_WIDTH, /* in pixels */ + XI_PREF_MULTILINE_QUICK_PASTE, + XI_PREF_COLOR_DISABLED, + XI_PREF_BUTTON_HEIGHT, + XI_PREF_BUTTON_PAD, + XI_PREF_HORZ_SPACING, + XI_PREF_VERT_SPACING, + XI_PREF_HORZ_PIXEL_SPACING, + XI_PREF_VERT_PIXEL_SPACING, + XI_PREF_ITF_MIN_TOP, /* in pixels */ + XI_PREF_ITF_MIN_LEFT, /* in pixels */ + XI_PREF_XIL, + XI_PREF_ASSERT_ON_NULL_CID, /* with xi_get_obj */ + XI_PREF_NO_BUTTON_SPACE, + XI_PREF_LASTPREF /* should always be last */ +} + +XI_PREF_TYPE; +typedef enum +{ + AGA_PREF_BTN_COLOR_LIGHT, + AGA_PREF_BTN_COLOR_CTRL, + AGA_PREF_BTN_COLOR_DARK, + AGA_PREF_BTN_COLOR_TEXT, + AGA_PREF_LASTPREF /* should always be last */ +} +AGA_PREF_TYPE; + +#define XI_NBR_PREFERENCES XI_PREF_LASTPREF +#define AGA_NBR_PREFERENCES AGA_PREF_LASTPREF + +/********************************** +* XI Bitmap structure +**********************************/ +typedef enum _xi_bitmap_mode +{ + XI_BITMAP_NORMAL, + XI_BITMAP_RESIZE, + XI_BITMAP_TILE +} XI_BITMAP_MODE; + +typedef struct _xi_bitmap +{ + XinBitmap* xin_bitmap; + XI_BITMAP_MODE mode; + long ref_count; + + /* The following properties are only used for XI_BITMAP_NORMAL */ + XinColor background; + short x_offset; + short y_offset; + BOOLEAN hcenter; + BOOLEAN vcenter; +} XI_BITMAP; + +/********************************** +* XI Object definition structures +**********************************/ +typedef enum _xi_btn_draw +{ + XIBT_DEFAULT, + XIBT_EMULATED, + XIBT_NATIVE +} XI_BTN_DRAW; + +typedef enum _xi_btn_type +{ + XIBT_BUTTON, + XIBT_CHECKBOX, + XIBT_RADIOBTN, + XIBT_TABBTN, + XIBT_BUTTON_CHECKBOX, + XIBT_BUTTON_RADIOBTN +} XI_BTN_TYPE; + +typedef enum _xi_obj_type +{ + XIT_BTN, + XIT_CONTAINER, + XIT_FORM, + XIT_FIELD, + XIT_GROUP, + XIT_LINE, + XIT_RECT, + XIT_TEXT, + XIT_CELL, + XIT_COLUMN, + XIT_ITF, + XIT_LIST, + XIT_ROW +} + +XI_OBJ_TYPE; + +typedef struct _xi_btn_def +{ + XI_BTN_TYPE type; + XinRect xi_rct; + XinRect pixel_rect; + unsigned long attrib; + char *text; + int tab_cid; + BOOLEAN dflt; + BOOLEAN cancel; + int down_icon_rid; + int up_icon_rid; + int disabled_icon_rid; + short icon_x; + short icon_y; + XI_BITMAP* down_bitmap; + XI_BITMAP* up_bitmap; + XI_BITMAP* disabled_bitmap; + BOOLEAN checked; + XinColor fore_color; + BOOLEAN drawable; + XI_BTN_DRAW draw_as; + char mnemonic; + short mnemonic_instance; + XinFont *font; +#ifndef XI_R4_API + XVT_FNTID font_id; +#endif +#ifdef XI_R3_COMPAT + void *font_id; +#endif +} XI_BTN_DEF; + +typedef enum +{ + XI_STACK_HORIZONTAL, + XI_STACK_VERTICAL, + XI_GRID_HORIZONTAL, + XI_GRID_VERTICAL +} + +XI_CONTAINER_ORIENTATION; + +typedef struct _xi_container_def +{ + XinRect xi_rct; + XinRect pixel_rect; + XI_CONTAINER_ORIENTATION orientation; + int tab_cid; + short btn_height; /* in form units */ + short btn_width; /* in form units */ + BOOLEAN packed; /* no space btwn btns, overlap 1 pixel in grid */ +} XI_CONTAINER_DEF; + +typedef struct _xi_field_def +{ + XinPoint pnt; /* form units */ + short field_width; /* form units */ + XinPoint pixel_origin; + short pixel_width; + short pixel_button_distance; + XinRect xi_rct; /* if set, use text edit module */ + unsigned long attrib; + int tab_cid; + short text_size; + XinColor back_color; + XinColor enabled_color; /* but inactive */ + XinColor disabled_color; + XinColor disabled_back_color; + XinColor active_color; + XinColor active_back_color; + XinColor hilight_color; /* for well and platform fields */ + XinColor shadow_color; /* for well and platform fields */ + BOOLEAN button; + BOOLEAN button_on_left; + XinFlag no_button_space; /* Is the button contained in the field's area? Defaults to preference. */ + int icon_rid; + XI_BITMAP* button_bitmap; + BOOLEAN well; + BOOLEAN platform; + BOOLEAN auto_tab; + BOOLEAN scroll_bar; + BOOLEAN cr_ok; + BOOLEAN var_len_text; + char mnemonic; + int button_width; /* Desired width of the button in pixels. */ + XinFont *font; +#ifndef XI_R4_API + XVT_FNTID font_id; +#endif +#ifdef XI_R3_COMPAT + void *font_id; +#endif +} XI_FIELD_DEF; + +typedef struct _xi_form_def +{ + int tab_cid; +} XI_FORM_DEF; + +typedef struct _xi_group_def +{ + short nbr_cids; + int *cids; +} XI_GROUP_DEF; + +typedef struct _xi_line_def +{ + XinPoint pnt1; + XinPoint pnt2; + XinPoint pixel_pnt1; + XinPoint pixel_pnt2; + XinColor fore_color; + XinColor back_color; + BOOLEAN well; + unsigned long attrib; +} XI_LINE_DEF; + +typedef struct _xi_rect_def +{ + XinRect xi_rct; + XinRect pixel_rect; + XinColor fore_color; + XinColor back_color; + XinColor hilight_color; + XinColor shadow_color; + BOOLEAN well; /* else platform */ + BOOLEAN ridge; + XI_BITMAP* bitmap; + unsigned long attrib; +} XI_RECT_DEF; + +typedef struct _xi_text_def +{ + XinRect xi_rct; + XinRect pixel_rect; + unsigned long attrib; + char *text; + XinColor fore_color; + XinColor back_color; + XinFont *font; + char mnemonic; + short mnemonic_instance; +#ifndef XI_R4_API + XVT_FNTID font_id; +#endif +#ifdef XI_R3_COMPAT + void *font_id; +#endif +} XI_TEXT_DEF; + +typedef enum _xi_icon_mode_type +{ + XIM_ICON_HAS_PRIORITY, + XIM_TEXT_WITH_ICON_ON_LEFT, + XIM_TEXT_WITH_ICON_ON_RIGHT, + XIM_TEXT_AND_BITMAP_OVERLAP +} + +XI_ICON_MODE_TYPE; + +typedef struct _xi_column_def +{ + unsigned long attrib; + short sort_number; + short width; /* form units */ + short pixel_width; /* alternate, pixel width */ + short text_size; + char *heading_text; + BOOLEAN center_heading; + BOOLEAN heading_well; + BOOLEAN heading_platform; + BOOLEAN column_well; + BOOLEAN column_platform; + short position; + XinFont *font; + int icon_rid; + short icon_x; + short icon_y; + XI_BITMAP* bitmap; + BOOLEAN size_rows; + BOOLEAN suppress_update_heading; + BOOLEAN suppress_update_cells; + BOOLEAN vertical_align_center; + BOOLEAN vertical_align_bottom; + BOOLEAN wrap_text; + BOOLEAN wrap_text_scrollbar; + BOOLEAN auto_tab; + BOOLEAN cr_ok; + BOOLEAN var_len_text; + char mnemonic; + XI_ICON_MODE_TYPE icon_mode; +#ifndef XI_R4_API + XVT_FNTID font_id; +#endif +#ifdef XI_R3_COMPAT + void *font_id; +#endif +} XI_COLUMN_DEF; + +typedef struct _xi_itf_def +{ + XI_EVENT_HANDLER xi_eh; + XinRect *rctp; + char *title; + BOOLEAN ctl_size; + BOOLEAN ctl_vscroll; + BOOLEAN ctl_hscroll; + BOOLEAN ctl_close; + BOOLEAN ctl_iconized; + BOOLEAN ctl_iconizable; + int menu_bar_rid; + XinWindow win; + XinWindow menu_win; + BOOLEAN size_win; /* automatically size window win */ + BOOLEAN edit_menu; + XinColor back_color; + BOOLEAN automatic_back_color; + unsigned long attrib; + BOOLEAN virtual_itf; + BOOLEAN modal; + BOOLEAN size_font_to_win; + BOOLEAN tab_on_enter; + BOOLEAN use_whitespace; + int whitespace_right; + int whitespace_bottom; + XinFont *font; + BOOLEAN use_xil_win; + BOOLEAN autoclose; + XI_BITMAP* bitmap; + BOOLEAN modal_wait; + BOOLEAN border_style_set; + XinBorderStyle border_style; + BOOLEAN visible; + BOOLEAN enabled; + BOOLEAN maximized; + XinWindow parent; + XinMenu *menu; + int icon_rid; + int initial_focus_cid; +#ifndef XI_R4_API + XVT_FNTID font_id; +#endif +#ifdef XI_R3_COMPAT + void *font_id; +#endif +} XI_ITF_DEF; + +typedef struct _xi_list_def +{ + XinPoint xi_pnt; + short height; + short width; + XinPoint pixel_origin; + short pixel_height; + short pixel_width; + unsigned long attrib; + XinColor back_color; + XinColor enabled_color; /* but inactive */ + XinColor disabled_color; + XinColor disabled_back_color; + XinColor active_color; + XinColor active_back_color; + XinColor white_space_color; + XinColor rule_color; + BOOLEAN no_heading; + BOOLEAN one_row_list; + BOOLEAN scroll_bar; + BOOLEAN sizable_columns; + BOOLEAN movable_columns; + BOOLEAN scroll_bar_button; + short fixed_columns; + int tab_cid; + short min_cell_height; + short min_heading_height; + BOOLEAN no_horz_lines; + BOOLEAN no_vert_lines; + int start_percent; + int first_vis_column; + BOOLEAN drop_and_delete; + BOOLEAN select_cells; + BOOLEAN get_all_records; + BOOLEAN resize_with_window; + XinFont *font; + int horz_sync_list; + int vert_sync_list; + BOOLEAN row_focus_border; + XinColor row_focus_border_color; + int max_lines_in_cell; + BOOLEAN single_select; + BOOLEAN retain_back_color_on_select; + BOOLEAN drag_and_drop_rows; + BOOLEAN drag_rows_autoscroll; + BOOLEAN button_on_cell_focus; + int position_by_typing_cid; + BOOLEAN scroll_on_thumb_track; +#ifndef XI_R4_API + XVT_FNTID font_id; +#endif +#ifdef XI_R3_COMPAT + void *font_id; +#endif +} XI_LIST_DEF; + +typedef struct _xi_obj_def +{ + XI_OBJ_TYPE type; + int cid; + struct _xi_obj_def *parent; + short nbr_children; + struct _xi_obj_def **children; + long app_data; + long app_data2; + char *help_key; + union + { + XI_BTN_DEF *btn; + XI_CONTAINER_DEF *container; + XI_FORM_DEF *form; + XI_FIELD_DEF *field; + XI_GROUP_DEF *group; + XI_LINE_DEF *line; + XI_RECT_DEF *rect; + XI_TEXT_DEF *text; + XI_COLUMN_DEF *column; + XI_ITF_DEF *itf; + XI_LIST_DEF *list; + } v; +} XI_OBJ_DEF; + +/********************************** +* XI Events +**********************************/ +typedef enum _xi_event_type +{ + XIE_CHAR_FIELD, + XIE_DBL_FIELD, + XIE_CHG_FIELD, + XIE_OFF_FIELD, + XIE_ON_FIELD, + XIE_OFF_GROUP, + XIE_ON_GROUP, + XIE_OFF_FORM, + XIE_ON_FORM, + XIE_VIR_PAN, + XIE_XIN_EVENT, + XIE_XIN_POST_EVENT, + XIE_INIT, + XIE_BUTTON, + XIE_CHAR_CELL, + XIE_CLEANUP, + XIE_CLOSE, + XIE_COMMAND, + XIE_DBL_CELL, + XIE_GET_FIRST, + XIE_GET_LAST, + XIE_GET_NEXT, + XIE_GET_PERCENT, + XIE_GET_PREV, + XIE_CELL_REQUEST, + XIE_CHG_CELL, + XIE_OFF_CELL, + XIE_ON_CELL, + XIE_OFF_ROW, + XIE_ON_ROW, + XIE_OFF_COLUMN, + XIE_ON_COLUMN, + XIE_OFF_LIST, + XIE_ON_LIST, + XIE_REC_ALLOCATE, + XIE_REC_FREE, + XIE_ROW_SIZE, + XIE_SELECT, + XIE_UPDATE, + XIE_COL_DELETE, + XIE_COL_MOVE, + XIE_COL_SIZE, + XIE_DROP_ROW, + XIE_POST_NAVIGATION, +#if defined(XI_R3_COMPAT) || !defined(XI_R4_API) + XIE_XVT_EVENT, + XIE_XVT_POST_EVENT, +#endif + XIE_LAST_EVENT +} + +XI_EVENT_TYPE; + +struct _xi_obj; + +typedef struct _xi_event +{ + XI_EVENT_TYPE type; + BOOLEAN refused; + union + { +#ifndef XI_R4_API + EVENT xvte; +#endif +#ifdef XI_R3_COMPAT + struct + { + int dummy; + } xvte; +#endif + XinEvent xin_event; + struct _xi_obj *xi_obj; + struct xit_rec_request + { + struct _xi_obj *list; + long spec_rec; + long data_rec; + short percent; + unsigned long attrib; + XinColor color; + int row_height; + BOOLEAN has_focus; + } rec_request; + struct xit_rec_allocate + { + struct _xi_obj *list; + long record; + } rec_allocate; + struct xit_rec_free + { + struct _xi_obj *list; + long record; + } rec_free; + struct xit_get_percent + { + struct _xi_obj *list; + long record; + short percent; + } get_percent; + struct xit_select + { + struct _xi_obj *xi_obj; + BOOLEAN selected; + BOOLEAN dbl_click; + BOOLEAN shift; + BOOLEAN control; + int column; + long *records; + } select; + struct xit_cell_request + { + struct _xi_obj *list; + char *s; + short len; + long rec; + short col_nbr; + int icon_rid; + XI_BITMAP* bitmap; + unsigned long attrib; + XinColor color; + XinColor back_color; + XinFont *font; + BOOLEAN button; + BOOLEAN button_on_left; + BOOLEAN button_on_focus; + BOOLEAN button_full_cell; + int button_icon_rid; + XI_BITMAP* button_bitmap; + long *records; +#ifndef XI_R4_API + XVT_FNTID font_id; +#endif +#ifdef XI_R3_COMPAT + void *font_id; +#endif + } cell_request; + struct xit_row_size + { + struct _xi_obj *xi_obj; + int new_row_height; + } row_size; + struct xit_cmd + { + int tag; + BOOLEAN shift; + BOOLEAN control; + } cmd; + struct xit_chr + { + struct _xi_obj *xi_obj; + int ch; + BOOLEAN shift; + BOOLEAN control; + BOOLEAN alt; + BOOLEAN is_paste; + } chr; + struct xit_vir_pan + { + BOOLEAN before_pan; /* else after */ + int delta_x; + int delta_y; + } vir_pan; + struct xit_column + { + struct _xi_obj *list; + int col_nbr; /* column to move, size, delete */ + int new_col_nbr; + BOOLEAN in_fixed; + int new_col_width; /* form units */ + int new_col_pixel_width; /* pixel units */ + } column; + struct xit_drop_row + { + struct _xi_obj* src_list; + struct _xi_obj* dest_list; + long src_rec; + long dest_rec; + BOOLEAN after_all_rows; + BOOLEAN delete_row; + BOOLEAN shift; + BOOLEAN control; + } drop_row; + long user_data; + } v; +} XI_EVENT; + + +/*************************************************** +* XI Object Macros +* Use these macros to fill in the appropriate +* fields of an XI_OBJ struct for synthesizing +* cells, rows, and columns. +***************************************************/ +#define XI_MAKE_CELL( objp, listobj, row_nbr, column_nbr ) \ + memset(( char* )objp, '\0', ( size_t )sizeof( XI_OBJ )), \ + (( objp )->itf = ( listobj )->parent, \ + ( objp )->parent = listobj, \ + ( objp )->type = XIT_CELL, \ + ( objp )->v.cell.row = row_nbr, \ + ( objp )->v.cell.column = column_nbr, \ + ( objp )->nbr_children = 0 ) + +#define XI_MAKE_ROW( objp, listobj, row_nbr ) \ + memset(( char* )objp, '\0', ( size_t )sizeof( XI_OBJ )), \ + (( objp )->itf = ( listobj )->parent, \ + ( objp )->parent = listobj, \ + ( objp )->type = XIT_ROW, \ + ( objp )->v.row = row_nbr, \ + ( objp )->nbr_children = 0 ) + +#define XI_MAKE_LIST( objp, listobj, row_nbr ) \ + memset(( char* )objp, '\0', ( size_t )sizeof( XI_OBJ )), \ + (( objp )->v.list = ( listobj )->parent, \ + ( objp )->parent = listobj, \ + ( objp )->type = XIT_LIST, \ + ( objp )->v.row = row_nbr, \ + ( objp )->nbr_children = 0 ) + +#ifndef max +#define max(A, B) ((A) > (B) ? (A) : (B)) +#endif + +#ifndef min +#define min(A, B) ((A) < (B) ? (A) : (B)) +#endif + +/*************************************************** +* XI Object data +* +* NOTE: Applications cannot use or rely upon data +* found in the XI_INTERNAL section of these structures +* Applications should use the non-XI_INTERNAL fields +* when referring to these objects. +* +* The cid field is unused for objects of type +* XIT_CELL, XIT_ROW and XIT_COLUMN +***************************************************/ + +#ifdef __cplusplus +struct _xi_column_data; +struct _xi_itf_data; +struct _xi_list_data; +struct _xi_container_data; +struct _xi_btn_data; +struct _xi_field_data; +struct _xi_form_data; +struct _xi_group_data; +struct _xi_line_data; +struct _xi_rect_data; +struct _xi_text_data; + +#define STRUCT +#else +#define STRUCT struct +#endif + +typedef struct _xi_cell_data +{ + unsigned char row; + unsigned char column; + unsigned char is_vert_scrolled; +} XI_CELL_DATA; + +typedef struct _xi_row_data +{ + short row; + unsigned char is_vert_scrolled; +} XI_ROW_DATA; + +typedef struct _xi_obj +{ + int cid; + struct _xi_obj *itf; + struct _xi_obj *parent; + XI_OBJ_TYPE type; + short nbr_children; + struct _xi_obj **children; + long app_data; + long app_data2; + char *help_key; + union + { + XI_CELL_DATA cell; + XI_ROW_DATA row_data; + short row; +#ifdef XI_INTERNAL + STRUCT _xi_column_data *column; + STRUCT _xi_itf_data *itf; + STRUCT _xi_list_data *list; + STRUCT _xi_container_data *container; + STRUCT _xi_btn_data *btn; + STRUCT _xi_field_data *field; + STRUCT _xi_form_data *form; + STRUCT _xi_group_data *group; + STRUCT _xi_line_data *line; + STRUCT _xi_rect_data *rect; + STRUCT _xi_text_data *text; +#else + /* so that union has room for a ptr */ + char *dummy; +#endif + } v; +} XI_OBJ; + +typedef void ( *XI_EH_TYPE ) ( XI_OBJ * itf, struct _xi_event * xiev ); + +#ifdef XI_INTERNAL +/* XI INTERNAL USE ONLY */ +typedef struct _xi_btn_data +{ + XI_BTN_TYPE type; + int tab_cid; + unsigned long attrib; + int down_icon_rid; + int up_icon_rid; + int disabled_icon_rid; + short icon_x; + short icon_y; + XI_BITMAP* down_bitmap; + XI_BITMAP* up_bitmap; + XI_BITMAP* disabled_bitmap; + XinWindow btnctl; + XinRect rct; /* bounding rectangle in pixels */ + XinRect xi_rct; /* original bounding rect in form units */ + char *text; + XinColor fore_color; + XI_BTN_DRAW draw_as; + BOOLEAN drawable; + BOOLEAN checked; + BOOLEAN down; + BOOLEAN down_in_btn; + BOOLEAN dflt; + BOOLEAN cancel; + BOOLEAN packed; /* no focus or default rect space */ + char mnemonic; + short mnemonic_instance; + XinFont *font; +} XI_BTN_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_container_data +{ + XinRect xi_rct; /* original container rect in form units */ + XI_CONTAINER_ORIENTATION orientation; + int tab_cid; + short btn_height; /* original button height in form units */ + short btn_width; /* original button width in form units */ + short nbr_buttons; /* number of buttons used in calculations */ + BOOLEAN packed; /* no padding or focus rect space */ + /* calculated */ + XinRect rct; + short nbr_down; /* number of buttons down in the container */ + short nbr_across; /* number of buttons across the container */ + short pix_height; /* button height in pixels */ + short pix_width; /* button width in pixels */ + short step_down; /* pixels from top edge to next top edge */ + short step_across; /* pixels from left edge to next left edge */ +} XI_CONTAINER_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_field_data +{ + STX stx; + int tab_cid; + XinRect xi_rct; + XinPoint xi_pnt; + int field_width; + XinRect rct; + BOOLEAN button; + BOOLEAN button_on_left; + XinFlag no_button_space; + int icon_rid; + XI_BITMAP* button_bitmap; + int button_width; /* disired pixel width of button */ + BOOLEAN down; + BOOLEAN down_in_btn; + XinRect btn_rct; + BOOLEAN well; + BOOLEAN platform; + BOOLEAN font_set; + BOOLEAN scroll_bar; + BOOLEAN cr_ok; + BOOLEAN var_len_text; + char mnemonic; +} XI_FIELD_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_form_data +{ + XI_OBJ *focus_field; + unsigned long attrib; + int tab_cid; +} XI_FORM_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_group_data +{ + short nbr_cids; + int *cidlist; + XI_OBJ **objlist; +} XI_GROUP_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_line_data +{ + XinPoint pnt1; + XinPoint pnt2; + XinPoint xi_pnt1; + XinPoint xi_pnt2; + XinColor fore_color; + XinColor back_color; + BOOLEAN well; + unsigned long attrib; +} XI_LINE_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_rect_data +{ + XinRect rct; + XinRect xi_rct; + XinColor fore_color; + XinColor back_color; + XinColor hilight_color; + XinColor shadow_color; + BOOLEAN well; + BOOLEAN ridge; + unsigned long attrib; + XI_BITMAP* bitmap; +} XI_RECT_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_text_data +{ + XinRect rct; + XinRect xi_rct; + short text_size; + char *text; + unsigned long attrib; + XinFont *font; + XinColor fore_color; + XinColor back_color; + char mnemonic; + short mnemonic_instance; +} XI_TEXT_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_column_data +{ + short sort_number; +} XI_COLUMN_DATA; + +/* XI INTERNAL USE ONLY */ +typedef struct _xi_itf_data +{ + unsigned short magic; + XinWindow xin_win; + XinWindow menu_win; + XI_EVENT_HANDLER xi_eh; + XI_OBJ *focus_obj; + XI_OBJ *trap_obj; + BOOLEAN trap_explicit; + BOOLEAN cursor_override; + XinCursor cursor; + BOOLEAN half_baked; + BOOLEAN edit_menu; + BOOLEAN paste_enable; + BOOLEAN cut_or_copy_enable; + XinColor back_color; + BOOLEAN automatic_back_color; + BOOLEAN virtual_itf; + BOOLEAN modal; + BOOLEAN size_font_to_win; + BOOLEAN tab_on_enter; + XI_BITMAP* bitmap; + BOOLEAN modal_wait; + XinRect original_win_rct; + int original_font_size; + XinWindow prev_modal; + XinPoint max_xi_pnt; + XinPoint phys_xi_pnt; + XinPoint win_xi_pnt; + int delta_x; + int delta_y; + int caret_x; + int caret_y; + int caret_height; + XinRect caret_clip; + BOOLEAN caret_is_on; + BOOLEAN mouse_is_down; + BOOLEAN closing; + int in_callback; + XI_OBJ *update_obj; + XinFont *font; + int fu_width; + int fu_height; + BOOLEAN moving_focus; + BOOLEAN chg_flag; + BOOLEAN use_xil_win; + BOOLEAN pasting; + XI_DEQUEUE_FLAG dequeue; + BOOLEAN in_event_destroy; + int initial_focus_cid; + BOOLEAN needs_update; +} XI_ITF_DATA; + +/* XI INTERNAL USE ONLY */ +#define FOCUS_CELL_ARRAY_LEN 6 +typedef struct _xi_list_data +{ + XinPoint xi_pnt; + int height; + int tab_cid; + BOOLEAN scroll_bar; + BOOLEAN one_row_list; + short sb_offset; + short sb_width; + BOOLEAN movable_columns; + BOOLEAN scroll_bar_button; + short width; + XI_OBJ *focus_cell; + XI_OBJ focus_cell_array[FOCUS_CELL_ARRAY_LEN]; + LM lm; + XinWindow sb_win; + XinWindow hsb_win; + XinRect sbb_rct; + BOOLEAN down_in_btn; + BOOLEAN down; + int start_percent; + XI_CELL_SPEC *cell_spec; + BOOLEAN have_sb_rct; + XinRect sb_rct; + BOOLEAN have_hsb_rct; + XinRect hsb_rct; + XinFont *font; + int horz_sync_list; + int vert_sync_list; + BOOLEAN row_focus_border; + XinColor row_focus_border_color; + int max_lines_in_cell; + BOOLEAN scrolling_in_progress; + BOOLEAN done_initial_xi_scroll; + BOOLEAN single_select; + BOOLEAN in_select_process; + int position_by_typing_cid; + BOOLEAN scroll_on_thumb_track; +} XI_LIST_DATA; + +#endif /* XI_INTERNAL */ + +/********************************** +* XI Metrics and preferences +**********************************/ +typedef enum +{ + XI_SV_FU_HEIGHT, + XI_SV_FU_WIDTH, + XI_SV_ITF_BORDER, + XI_SV_SYSFONT_HEIGHT, + XI_SV_SYSFONT_ASCENT, + XI_SV_SYSFONT_DESCENT, + XI_SV_SYSFONT_LEADING, + XI_SV_LASTSV /* should always be last */ +} + +XI_SV_TYPE; + +#define XI_NBR_SYSVALS XI_SV_LASTSV + +typedef struct _xi_eq +{ + XI_EVENT xiev; + XI_OBJ *itf; + struct _xi_eq *next; +} XI_EQ; + +typedef struct _xi_window_list +{ + struct _xi_window_list *next; + XinWindow win; + XI_OBJ *itf; +} XI_WINDOW_LIST; + +typedef struct _xi_scroll_record_arg +{ + XI_OBJ *xi_obj; + long record; + XinColor row_color; + unsigned long attrib; + int row_height; + BOOLEAN rec_at_top; +} XI_SCROLL_RECORD_ARG; + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef XI_R4_API +#define xi_init() xi_init_internal( TRUE ) +#define xi_create( a, b ) xi_create_internal( (a), (b), FALSE, TRUE ) +#define xi_get_def_rect( a, b ) xi_get_def_rect_internal( (a), (b), TRUE ) +#else +#define xi_init() xi_init_internal( FALSE ) +#define xi_create( a, b ) xi_create_internal( (a), (b), FALSE, FALSE ) +#define xi_get_def_rect( a, b ) xi_get_def_rect_internal( (a), (b), FALSE ) +#endif + +XIDLL XI_OBJ_DEF * xi_add_button_def XVT_CC_ARGS( ( XI_OBJ_DEF * parent, + int cid, XinRect * rct, + unsigned long attrib, char *text, + int tab_cid ) ); +XIDLL XI_OBJ_DEF * xi_add_container_def XVT_CC_ARGS( ( XI_OBJ_DEF * itf, + int cid, XinRect * xi_rct, + XI_CONTAINER_ORIENTATION orientation, + int tab_cid ) ); +XIDLL XI_OBJ_DEF * xi_add_field_def XVT_CC_ARGS( ( XI_OBJ_DEF * form, + int cid, int v, int h, + int field_width, + unsigned long attrib, int tab_cid, + int text_size, XinColor enabled_color, + XinColor back_color, + XinColor disabled_color, + XinColor disabled_back_color, + XinColor active_color ) ); +XIDLL XI_OBJ_DEF * xi_add_form_def XVT_CC_ARGS( ( XI_OBJ_DEF * itf, int cid, + int tab_cid ) ); +XIDLL XI_OBJ_DEF * xi_add_group_def XVT_CC_ARGS( ( XI_OBJ_DEF * object, + int cid, int nbr_cids, + int *cid_list ) ); +XIDLL XI_OBJ_DEF * xi_add_line_def XVT_CC_ARGS( ( XI_OBJ_DEF * itf, int cid, + XinPoint * pnt1, XinPoint * pnt2, + unsigned long attrib, + XinColor fore_color, XinColor back_color, + BOOLEAN well ) ); +XIDLL XI_OBJ_DEF * xi_add_rect_def XVT_CC_ARGS( ( XI_OBJ_DEF * itf, int cid, + XinRect * rct, unsigned long attrib, + XinColor fore_color, XinColor back_color ) ); +XIDLL XI_OBJ_DEF * xi_add_text_def XVT_CC_ARGS( ( XI_OBJ_DEF * itf, int cid, + XinRect * rct, unsigned long attrib, + char *text ) ); +XIDLL int xi_button_calc_pixel_height XVT_CC_ARGS( ( int height ) ); +XIDLL int xi_button_calc_pixel_width XVT_CC_ARGS( ( int width ) ); +XIDLL int xi_button_def_get_width XVT_CC_ARGS( ( XI_OBJ_DEF * obj_def ) ); +XIDLL void xi_check XVT_CC_ARGS( ( XI_OBJ * xi_obj, BOOLEAN check ) ); +XIDLL void xi_clean_up XVT_CC_ARGS( ( void ) ); +XIDLL int xi_container_def_get_btn_width XVT_CC_ARGS( ( XI_OBJ_DEF * obj_def ) ); +XIDLL int xi_container_def_get_height XVT_CC_ARGS( ( XI_OBJ_DEF * obj_def ) ); +XIDLL int xi_container_def_get_width XVT_CC_ARGS( ( XI_OBJ_DEF * obj_def ) ); +XIDLL void xi_container_reorient XVT_CC_ARGS( ( XI_OBJ * cnt_obj, + XI_CONTAINER_DEF * cnt_def ) ); +XIDLL void xi_def_free XVT_CC_ARGS( ( XI_OBJ_DEF* obj_def ) ); +XIDLL int xi_get_fixed_columns XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL void xi_get_font_metrics_font( XinFont * font, int *leading, int *ascent, + int *descent, int *char_width ); +XIDLL long xi_get_handle XVT_CC_ARGS( ( XI_OBJ * list, XI_OBJ * child_obj ) ); +XIDLL BOOLEAN xi_is_checked XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL void xi_set_fixed_columns XVT_CC_ARGS( ( XI_OBJ * xi_obj, + int fixed_columns ) ); +XIDLL void xi_set_fore_color XVT_CC_ARGS( ( XI_OBJ * xi_obj, + XinColor color ) ); +XIDLL void xi_vir_pan XVT_CC_ARGS( ( XI_OBJ * xi_obj, int delta_x, + int delta_y ) ); +XIDLL int xi_button_calc_height_font XVT_CC_ARGS( ( XinFont * font ) ); +XIDLL int xi_field_calc_height_font XVT_CC_ARGS( ( XinFont * font ) ); +XIDLL int xi_field_calc_width_font XVT_CC_ARGS( ( XinFont * font, + char *string ) ); +#ifndef XI_R4_API +XIDLL int xi_button_calc_height_font_id XVT_CC_ARGS( ( XVT_FNTID font ) ); +XIDLL int xi_field_calc_height_font_id XVT_CC_ARGS( ( XVT_FNTID font ) ); +XIDLL int xi_field_calc_width_font_id XVT_CC_ARGS( ( XVT_FNTID font, + char *string ) ); +#endif +XIDLL XI_OBJ_DEF * xi_add_column_def XVT_CC_ARGS( ( XI_OBJ_DEF * list, + int cid, unsigned long attrib, + int sort_number, int width, + int text_size, char *heading_text ) ); +XIDLL XI_OBJ_DEF * xi_add_list_def XVT_CC_ARGS( ( XI_OBJ_DEF * itf, int cid, + int v, int h, int height, + unsigned long attrib, + XinColor enabled_color, XinColor back_color, + XinColor disabled_color, + XinColor disabled_back_color, + XinColor active_color, int tab_cid ) ); +XIDLL BOOLEAN xi_button_set_default XVT_CC_ARGS( ( XI_OBJ * xi_obj, + BOOLEAN set ) ); +XIDLL void xi_cell_request XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL XI_OBJ * xi_create_internal XVT_CC_ARGS( ( XI_OBJ * parent, + XI_OBJ_DEF * xi_obj_def, + BOOLEAN special, + BOOLEAN r4_api ) ); +XIDLL XI_OBJ_DEF * xi_create_itf_def XVT_CC_ARGS( ( int cid, + XI_EVENT_HANDLER xi_eh, XinRect * rctp, + char *title, long app_data ) ); +XIDLL void xi_delete XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL BOOLEAN xi_delete_row XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL void xi_dequeue XVT_CC_ARGS( ( void ) ); +#ifdef XI_R4_API +XIDLL void xi_event XVT_CC_ARGS( ( XinWindow win, XinEvent * ep ) ); +#else +#define xi_event XinXvtEventHandler +XIDLL long XinXvtEventHandler XVT_CC_ARGS( ( WINDOW win, EVENT * ep ) ); +#endif +XIDLL void xi_force_focus_cell_visible XVT_CC_ARGS( ( XI_OBJ * list ) ); +XIDLL BOOLEAN xi_cell_data_valid( XI_OBJ * cell ); +XIDLL void xi_fu_to_pu XVT_CC_ARGS( ( XI_OBJ * itf, XinPoint * pnts, + int nbr_pnts ) ); +XIDLL long xi_get_app_data XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL long xi_get_app_data2 XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL unsigned long xi_get_attrib XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); + XI_CELL_SPEC * xi_get_cell_selection XVT_CC_ARGS( ( XI_OBJ * list, + int *nbr_cells ) ); +XIDLL XI_OBJ_DEF * xi_get_def XVT_CC_ARGS( ( XI_OBJ * obj ) ); +XIDLL XinRect * xi_get_def_rect_internal XVT_CC_ARGS( ( XI_OBJ_DEF * xi_obj_def, + XinRect * rctp, + BOOLEAN r4_api ) ); +XIDLL XI_OBJ * xi_get_focus XVT_CC_ARGS( ( XI_OBJ * itf ) ); +XIDLL XI_OBJ * xi_get_itf XVT_CC_ARGS( ( XinWindow win ) ); +XIDLL XI_OBJ_DEF * xi_get_list_def XVT_CC_ARGS( ( XI_OBJ * list ) ); +XIDLL long * xi_get_list_info XVT_CC_ARGS( ( XI_OBJ * list, + int *nbr_recs ) ); +XIDLL XI_OBJ ** xi_get_member_list XVT_CC_ARGS( ( XI_OBJ * xi_obj, + int *nbr_members ) ); +XIDLL long xi_get_pref XVT_CC_ARGS( ( XI_PREF_TYPE preftype ) ); +XIDLL XI_OBJ * xi_get_obj XVT_CC_ARGS( ( XI_OBJ * itf, int cid ) ); +XIDLL XinRect * xi_get_rect XVT_CC_ARGS( ( XI_OBJ * xi_obj, XinRect * rctp ) ); +XIDLL void xi_set_rect XVT_CC_ARGS( ( XI_OBJ * xi_obj, XinRect * rctp, + BOOLEAN do_invalidates ) ); +XIDLL void xi_get_sel XVT_CC_ARGS( ( XI_OBJ * xi_obj, int *selstart, + int *selstop ) ); +XIDLL XinFont * xi_get_system_font XVT_CC_ARGS( ( void ) ); +XIDLL int xi_get_sysval XVT_CC_ARGS( ( XI_SV_TYPE valtype ) ); +XIDLL char * xi_get_text XVT_CC_ARGS( ( XI_OBJ * xi_obj, char *s, + int len ) ); +XIDLL XinWindow xi_get_window XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL int xi_get_visible_rows XVT_CC_ARGS( ( XI_OBJ * xi_obj, + int *first_vis, int *last_vis ) ); +XIDLL void xi_get_visible_columns XVT_CC_ARGS( ( XI_OBJ * xi_obj, + int *first_vis, + int *last_vis ) ); +XIDLL void xi_set_fixed_columns XVT_CC_ARGS( ( XI_OBJ * xi_obj, + int new_fixed_count ) ); +XIDLL XinRect * xi_get_xi_rct XVT_CC_ARGS( ( XI_OBJ * itf, + XinRect * xi_rct ) ); +XIDLL XI_OBJ* xi_get_itf_containing XVT_CC_ARGS( ( XinPoint* pt ) ); + +XIDLL BOOLEAN xi_def_get_xil_pref( XI_OBJ_DEF* obj_def ); +XIDLL void xi_init_internal XVT_CC_ARGS( ( BOOLEAN r4_api ) ); +XIDLL BOOLEAN xi_insert_row XVT_CC_ARGS( ( XI_OBJ * list, int row ) ); +XIDLL BOOLEAN xi_is_changed XVT_CC_ARGS( ( XI_OBJ * obj ) ); +XIDLL BOOLEAN xi_is_itf XVT_CC_ARGS( ( XI_OBJ * itf ) ); +XIDLL BOOLEAN xi_is_window XVT_CC_ARGS( ( XinWindow win ) ); +XIDLL BOOLEAN xi_is_focus_moving XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL BOOLEAN xi_is_auto_tab XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL BOOLEAN xi_itf_closing_is XVT_CC_ARGS( ( XI_OBJ * itf ) ); +XIDLL BOOLEAN xi_itf_in_event_destroy( XI_OBJ * itf ); + +XIDLL int xi_list_def_get_client_height XVT_CC_ARGS( ( + XI_OBJ_DEF * list_def, + int rows ) ); +XIDLL int xi_list_def_get_client_width XVT_CC_ARGS( ( + XI_OBJ_DEF * obj_def, + int columns ) ); +XIDLL int xi_list_def_get_outer_height XVT_CC_ARGS( ( + XI_OBJ_DEF * list_def, + int rows ) ); +XIDLL int xi_list_def_get_outer_width XVT_CC_ARGS( ( + XI_OBJ_DEF * obj_def, + int columns ) ); +XIDLL int xi_list_def_get_rows XVT_CC_ARGS( ( XI_OBJ_DEF * list_def ) ); + +XIDLL void xi_move_column XVT_CC_ARGS( ( XI_OBJ * column, + int position ) ); +XIDLL BOOLEAN xi_move_focus XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL void xi_pu_to_fu XVT_CC_ARGS( ( XI_OBJ * itf, XinPoint * pnts, int nbr_pnts ) ); +XIDLL int xi_scroll XVT_CC_ARGS( ( XI_OBJ * xi_obj, int nbr_lines ) ); +XIDLL int xi_scroll_rec XVT_CC_ARGS( ( XI_OBJ * xi_obj, long record, XinColor row_color, unsigned + long attrib, int row_height ) ); +XIDLL int xi_scroll_record XVT_CC_ARGS( ( XI_SCROLL_RECORD_ARG * arg ) ); +XIDLL int xi_scroll_percent XVT_CC_ARGS( ( XI_OBJ * xi_obj, int percent ) ); +XIDLL void xi_set_app_data XVT_CC_ARGS( ( XI_OBJ * xi_obj, long app_data ) ); +XIDLL void xi_set_app_data2 XVT_CC_ARGS( ( XI_OBJ * xi_obj, long app_data2 ) ); +XIDLL void xi_set_attrib XVT_CC_ARGS( ( XI_OBJ * xi_obj, unsigned long attrib ) ); +XIDLL void xi_set_bufsize XVT_CC_ARGS( ( XI_OBJ * xi_obj, int size ) ); +XIDLL void xi_set_color XVT_CC_ARGS( ( XI_OBJ * xi_obj, XI_COLOR_PART part, XinColor color ) ); +XIDLL void xi_set_column_width XVT_CC_ARGS( ( XI_OBJ * xi_obj, + int width ) ); +XIDLL void xi_column_set_pixel_width XVT_CC_ARGS( ( XI_OBJ * xi_obj, + int width ) ); +XIDLL void xi_set_focus XVT_CC_ARGS( ( XI_OBJ * xi_obj ) ); +XIDLL void xi_set_font XVT_CC_ARGS( ( XinFont * font ) ); +#ifndef XI_R4_API +XIDLL void xi_set_font_id XVT_CC_ARGS( ( XVT_FNTID font_id ) ); +#else +XIDLL void xi_set_font_id XVT_CC_ARGS( ( void* font_id ) ); +#endif +XIDLL void xi_set_list_size XVT_CC_ARGS( ( XI_OBJ * xi_obj, int height, int width ) ); +XIDLL void xi_set_obj_font XVT_CC_ARGS( ( XI_OBJ * xi_obj, XinFont * font ) ); +#ifndef XI_R4_API +XIDLL void xi_set_obj_font_id XVT_CC_ARGS( ( XI_OBJ * xi_obj, XVT_FNTID font_id ) ); +#else +XIDLL void xi_set_obj_font_id XVT_CC_ARGS( ( XI_OBJ * xi_obj, void* font_id ) ); +#endif +XIDLL void xi_set_bitmap XVT_CC_ARGS( ( XI_OBJ* xi_obj, XI_BITMAP* bitmap ) ); +XIDLL void xi_set_down_bitmap XVT_CC_ARGS( ( XI_OBJ* xi_obj, XI_BITMAP* bitmap ) ); +XIDLL void xi_set_icon XVT_CC_ARGS( ( XI_OBJ * xi_obj, int icon_rid, int down_icon_rid ) ); +XIDLL void xi_set_pref XVT_CC_ARGS( ( XI_PREF_TYPE preftype, long value ) ); +XIDLL void xi_set_sel XVT_CC_ARGS( ( XI_OBJ * xi_obj, int selstart, int selstop ) ); +XIDLL void xi_set_row_height XVT_CC_ARGS( ( XI_OBJ * xi_obj, int height ) ); +XIDLL void xi_set_text XVT_CC_ARGS( ( XI_OBJ * xi_obj, const char *s ) ); +XIDLL void xi_set_override_cursor XVT_CC_ARGS( ( XI_OBJ* itf, XinCursor cursor, BOOLEAN flag ) ); +XIDLL void xi_event_debug XVT_CC_ARGS( ( char *tag, XI_EVENT * xiev, char *s, int len ) ); + +XIDLL char * gstrncpy XVT_CC_ARGS( ( char *dst, const char *src, int n ) ); + + /* XI consistant drawing functions - these functions perform identically on + * all platforms. These functions also do virtual interface coordinate + * conversion. */ +XIDLL void xi_draw_3d_diamond XVT_CC_ARGS( ( XinWindow win, XinRect * rctp, BOOLEAN well, BOOLEAN black, + int height, XinColor color ) ); +XIDLL void xi_draw_3d_line XVT_CC_ARGS( ( XinWindow win, XinPoint pnt1, XinPoint pnt2, BOOLEAN well ) ); +XIDLL void xi_draw_3d_rect XVT_CC_ARGS( ( XinWindow win, XinRect * rctp, BOOLEAN well, int height, XinColor + color_light, XinColor color_ctrl, XinColor color_dark ) ); +XIDLL void xi_draw_shaded_rect XVT_CC_ARGS( ( XinWindow win, XinRect * rctp, BOOLEAN well, int height, XinColor + color_light, XinColor color_ctrl, XinColor color_dark ) ); +XIDLL void xi_draw_diamond XVT_CC_ARGS( ( XinWindow win, XinRect * rctp, BOOLEAN well, BOOLEAN black, BOOLEAN fill, XinColor color ) ); +XIDLL void xi_draw_checkmark XVT_CC_ARGS( ( XinWindow win, XinRect * rctp ) ); + +XIDLL void xi_draw_text_attrib XVT_CC_ARGS( ( XinWindow win, XinFont * font, int x, int y, char *s, int len, unsigned + long attrib ) ); +XIDLL void xi_draw_thick_rect XVT_CC_ARGS( ( XinWindow win, XinRect * rctp, int width ) ); +XIDLL BOOLEAN xi_rect_intersect XVT_CC_ARGS( ( XinRect * rctp, XinRect * rctp1, XinRect * rctp2 ) ); +XIDLL void xi_offset_rect( XinRect * rct, int delta_h, int delta_v ); +XIDLL void xi_invalidate_rect( XinWindow win, XinRect * rctp ); +XIDLL void xi_draw_rect( XinWindow win, XinRect * rctp ); +XIDLL void xi_draw_roundrect( XinWindow win, XinRect * rctp, int rh, int rv ); + +XIDLL void xi_draw_line( XinWindow win, XinPoint p ); +XIDLL void xi_move_to( XinWindow win, XinPoint p ); + +/****************************************************************** +Tree module +******************************************************************/ +#ifdef TREEDEBUG +#define xi_tree_malloc( size, parent ) \ +xi_tree_malloc_d( size, parent, __LINE__, __FILE__ ) +#define xi_tree_realloc( p, size ) \ +xi_tree_realloc_d( p, size, __LINE__, __FILE__ ) +#endif +#ifdef TREEDEBUG +XIDLL void * xi_tree_malloc_d XVT_CC_ARGS( ( size_t size, void *parent, int line, + char *file ) ); +XIDLL void * xi_tree_realloc_d XVT_CC_ARGS( ( void *p, size_t size, int line, char *file ) ); +#else +XIDLL void * xi_tree_malloc XVT_CC_ARGS( ( size_t size, void *parent ) ); +XIDLL void * xi_tree_realloc XVT_CC_ARGS( ( void *p, size_t size ) ); +#endif +XIDLL void xi_tree_reparent XVT_CC_ARGS( ( void *p, void *parent ) ); +XIDLL void xi_tree_free XVT_CC_ARGS( ( void *p ) ); +XIDLL void * xi_tree_get_parent XVT_CC_ARGS( ( void *p ) ); +XIDLL void xi_tree_dbg XVT_CC_ARGS( ( char *title ) ); +XIDLL void xi_tree_check_sanity XVT_CC_ARGS( ( char *title ) ); +XIDLL void xi_tree_reg_error_fcn XVT_CC_ARGS( ( void ( *fcn ) ( void ) ) ); +XIDLL void aga_set_pref XVT_CC_ARGS((AGA_PREF_TYPE preftype, long value)); +XIDLL long aga_get_pref XVT_CC_ARGS((AGA_PREF_TYPE preftype)); + +/* Bitmap functions and macros */ +XIDLL XI_BITMAP* xi_bitmap_create XVT_CC_ARGS( ( char* filename, XI_BITMAP_MODE mode ) ); +XIDLL XI_BITMAP* xi_bitmap_create_res XVT_CC_ARGS( ( short id, XI_BITMAP_MODE mode ) ); + +XIDLL XI_BITMAP* xi_bitmap_copy XVT_CC_ARGS( ( XI_BITMAP* bitmap ) ); +XIDLL void xi_bitmap_destroy XVT_CC_ARGS( ( XI_BITMAP* bitmap ) ); +XIDLL void xi_bitmap_draw XVT_CC_ARGS( ( XI_BITMAP* bitmap, XinWindow win, + XinRect* rct, XinRect* clip_rct, + BOOLEAN in_paint_event ) ); +XIDLL void xi_bitmap_size_get XVT_CC_ARGS( ( XI_BITMAP* bitmap, short* width, + short* height ) ); +XIDLL BOOLEAN xi_bitmap_draw_all_on_resize XVT_CC_ARGS( ( XI_BITMAP* bitmap ) ); + +XIDLL void xi_aga_field_set_caret_pos( XI_OBJ * xi_obj, int pos ); +XIDLL void xi_lowlevel_focus( XI_OBJ * xi_obj, BOOLEAN set); + +#define xi_bitmap_background_set( bitmap, color ) ((bitmap)->background = (color) ) +#define xi_bitmap_hcenter_set( bitmap, flag ) ((bitmap)->hcenter = (flag) ) +#define xi_bitmap_mode_set( bitmap, m ) ((bitmap)->mode = (m) ) +#define xi_bitmap_offset_x_set( bitmap, x ) ((bitmap)->x_offset = (x) ) +#define xi_bitmap_offset_y_set( bitmap, y ) ((bitmap)->y_offset = (y) ) +#define xi_bitmap_vcenter_set( bitmap, flag ) ((bitmap)->vcenter = (flag) ) + +#define xi_bitmap_background_get( bitmap ) ((bitmap)->background) +#define xi_bitmap_hcenter_get( bitmap ) ((bitmap)->hcenter) +#define xi_bitmap_mode_get( bitmap ) ((bitmap)->mode) +#define xi_bitmap_offset_x_get( bitmap ) ((bitmap)->x_offset) +#define xi_bitmap_offset_y_get( bitmap ) ((bitmap)->y_offset) +#define xi_bitmap_vcenter_get( bitmap ) ((bitmap)->vcenter) + +#ifdef __cplusplus +} + +/* End of extern "C" */ +#endif + +#endif /* INCL_XI */ diff --git a/src/xi01/xi2.c b/src/xi01/xi2.c new file mode 100644 index 000000000..f74b8886e --- /dev/null +++ b/src/xi01/xi2.c @@ -0,0 +1,4014 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#define XI_R3_COMPAT +#include "xi.h" +#include "xitext.h" +#include "xistx.h" +#include "xilm.h" +#include "xilmst.h" +#include "xiutils.h" +#include "xi_int.h" + +#if XIWS == XIWS_XM +#include +#include +#endif + +#if XIWS == XIWS_WM +#define BORDER_WIDTH 8 +#define EDIT_BORDER_WIDTH_Y 0 +#define EDIT_BORDER_SPACE_Y 0 +#else +#define BORDER_WIDTH 2 +#define EDIT_BORDER_WIDTH_Y 1 +#define EDIT_BORDER_SPACE_Y 1 +#endif + +/******************************* STATIC DATA ********************************/ +typedef struct s_xi_interface_create_data +{ + XinRect rct; + XI_OBJ_DEF *obj_def; + XI_OBJ *itf; +} XI_INTERFACE_CREATE_DATA; + +static XI_EQ *xi_eq; +static BOOLEAN inited = FALSE; +static XI_WINDOW_LIST *xi_window_list; +static char *list_parent; +extern XinWindow xi_modal_win; +BOOLEAN xi_in_modal_wait_create = FALSE; +static XI_INTERFACE_CREATE_DATA interface_create_data; +XI_OBJ *xi_creating_itf = NULL; + +/******************************** FUNCTIONS *********************************/ +BOOLEAN +xi_compare_objs( XI_OBJ * obj_one, XI_OBJ * obj_two ) +{ + if ( obj_one == obj_two ) + return ( TRUE ); + if ( obj_two != NULL && obj_two->type == XIT_CELL + && obj_one != NULL && obj_one->type == XIT_CELL + && obj_two->parent == obj_one->parent ) + { + XI_CELL_DATA *cell_one_cell_data = &obj_one->v.cell; + XI_CELL_DATA *cell_two_cell_data = &obj_two->v.cell; + + return cell_one_cell_data->row == cell_two_cell_data->row + && cell_one_cell_data->column == cell_two_cell_data->column + && cell_one_cell_data->is_vert_scrolled == cell_two_cell_data->is_vert_scrolled; + } + return FALSE; +} + + +static XI_OBJ * +get_non_focus_cell_obj( XI_LIST_DATA * list_data ) +{ + int i; + + for ( i = 0; i < FOCUS_CELL_ARRAY_LEN; ++i ) + if ( list_data->focus_cell == &list_data->focus_cell_array[i] ) + break; + i = ( i + 1 ) % FOCUS_CELL_ARRAY_LEN; + return &list_data->focus_cell_array[i]; +} + +XI_OBJ * +xi_search_itf( XI_OBJ * xi_obj, + XI_SEARCH_TYPE search_type, int parm1 ) +{ + XI_OBJ *obj; + XI_OBJ **objp; + int i, + column, + tab_cid; + unsigned long attrib; + XI_OBJ *cell_obj; + XI_LIST_DATA *list_data; + LM lm; + + switch ( search_type ) + { + case XI_SEARCH_FOR_FOCUSABLE: + switch ( xi_obj->type ) + { + case XIT_LIST: + lm = xi_obj->v.list->lm; + attrib = lm_get_attrib( lm, LM_LIST, 0, 0, FALSE ); + if ( ( attrib & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) != + ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + return NULL; + return ( xi_obj ); + case XIT_CELL: + return ( xi_obj ); + case XIT_COLUMN: + lm = xi_obj->parent->v.list->lm; + attrib = lm_get_attrib( lm, LM_LIST, 0, 0, FALSE ); + if ( ( attrib & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) != + ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + return NULL; + column = xi_obj_to_idx( xi_obj ); + attrib = lm_get_attrib( lm, LM_COLUMN, column, 0, FALSE ); + if ( ( attrib & + ( XI_ATR_ENABLED | XI_ATR_SELECTABLE | XI_ATR_VISIBLE ) ) + != ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + return NULL; + else + { + list_data = xi_obj->parent->v.list; + cell_obj = get_non_focus_cell_obj( list_data ); + cell_obj->v.cell.row = 0; + cell_obj->v.cell.column = ( unsigned char ) column; + return ( cell_obj ); + } + case XIT_FIELD: + attrib = stx_get_attrib( xi_obj->v.field->stx ); + if ( ( attrib & XI_ATR_ENABLED ) != 0 && + ( attrib & XI_ATR_VISIBLE ) != 0 ) + return ( xi_obj ); + else + return NULL; + case XIT_BTN: +#if XIWS == XIWS_MAC + if ( xi_get_native_controls( xi_obj ) ) + return NULL; +#endif + { + unsigned long attrib; + + attrib = xi_obj->v.btn->attrib; + if ( ( attrib & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) == + ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + return xi_obj; + else + return NULL; + } + case XIT_GROUP: + return NULL; + default: + break; + } + break; + case XI_SEARCH_FOR_TAB_CID: + switch ( xi_obj->type ) + { + case XIT_FIELD: + tab_cid = xi_obj->v.field->tab_cid; + break; + case XIT_BTN: + tab_cid = xi_obj->v.btn->tab_cid; + break; + case XIT_FORM: + tab_cid = xi_obj->v.form->tab_cid; + break; + case XIT_CONTAINER: + tab_cid = xi_obj->v.container->tab_cid; + break; + case XIT_LIST: + tab_cid = xi_obj->v.list->tab_cid; + break; + default: + tab_cid = -1; + break; + } + if ( tab_cid == parm1 ) + return xi_obj; + break; + case XI_SEARCH_FOR_FIELD: + if ( xi_obj->type == XIT_FIELD ) + return xi_obj; + break; + case XI_SEARCH_FOR_INITIAL: + if (xi_obj->type == XIT_ITF && xi_obj->v.itf->initial_focus_cid != 0) + { + XI_OBJ *new_obj = xi_get_obj( xi_obj, xi_obj->v.itf->initial_focus_cid ); + if ( ( xi_get_attrib( new_obj ) & ( XI_ATR_ENABLED | + XI_ATR_VISIBLE ) ) == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + return new_obj; + } + return xi_search_itf( xi_obj, XI_SEARCH_FOR_FOCUSABLE, parm1 ); + default: + XinError( 20002, XinSeverityFatal, 0L ); + } + /* search child list */ + objp = xi_obj->children; + obj = NULL; + for ( i = xi_obj->nbr_children; i > 0 && obj == NULL; i--, objp++ ) + obj = xi_search_itf( *objp, search_type, parm1 ); + return obj; +} + +static void +xi_remove_from_parent_list( XI_OBJ * xi_obj ) +{ + XI_OBJ *parent; + XI_OBJ **list; + int n; + BOOLEAN copying_down = FALSE; + + if ( ( parent = xi_obj->parent ) == NULL ) + return; + list = parent->children; + n = parent->nbr_children; + for ( ; n > 0; n--, list++ ) + { + if ( copying_down ) + list[-1] = *list; + if ( *list == xi_obj ) + copying_down = TRUE; + } + /* error if we did not find the child in the list */ + if ( !copying_down ) + XinError( 20001, XinSeverityFatal, 0L ); + parent->nbr_children--; +} + +/* + xi_find_next_obj: find the next control in the tabbing sequence. + The focus_obj parameter indicates the object that currently has + the focus. + The type of navigation is given by the tab_type parameter. +*/ +XI_OBJ * +xi_find_next_obj( XI_OBJ * focus_obj, XI_NEXT_TYPE tab_type, long c ) +{ + XI_OBJ_TYPE type; + XI_OBJ *itf, *obj = NULL; + int tab_cid = 0; + + if ( focus_obj == NULL || focus_obj->type == XIT_ITF ) + { + /* find the first thing on the interface */ + return ( xi_search_itf( focus_obj->itf, XI_SEARCH_FOR_FOCUSABLE, 0 ) ); + } + + type = focus_obj->type; + itf = focus_obj->itf; + switch ( tab_type ) + { + case XI_NEXT_FORM_TAB: + case XI_NEXT_ITF_TAB: + switch ( tab_type ) + { + case XI_NEXT_FORM_TAB: + if ( type == XIT_FORM ) + return ( xi_search_itf( itf, XI_SEARCH_FOR_FIELD, 0 ) ); + obj = focus_obj; + break; + case XI_NEXT_ITF_TAB: + obj = focus_obj->parent; + if ( obj->type == XIT_ITF ) /* No container, ignore it */ + return NULL; + break; + default: + break; + } + while ( TRUE ) + { + switch ( obj->type ) + { + case XIT_FIELD: + tab_cid = obj->v.field->tab_cid; + break; + case XIT_BTN: + tab_cid = obj->v.btn->tab_cid; + break; + case XIT_FORM: + tab_cid = obj->v.form->tab_cid; + break; + case XIT_LIST: + tab_cid = obj->v.list->tab_cid; + break; + case XIT_CONTAINER: + tab_cid = obj->v.container->tab_cid; + break; + case XIT_COLUMN: + tab_cid = obj->cid + 1; + break; + default: + XinError( 20003, XinSeverityFatal, 0L ); + break; + } + obj = xi_get_obj( itf, tab_cid ); + if ( obj == NULL || obj == focus_obj ) + break; +#if XIWS == XIWS_MAC + if ( xi_get_native_controls( obj ) + && ( obj->type == XIT_BTN || obj->type == XIT_CONTAINER ) ) + continue; +#endif + if ( + ( xi_get_attrib( obj ) & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) != + ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + continue; + if ( obj->type == XIT_LIST ) + { + int i, + nbr_members; + XI_OBJ **members; + BOOLEAN have_column; + + members = xi_get_member_list( obj, &nbr_members ); + have_column = FALSE; + for ( i = 0; i < nbr_members; ++i ) + { + unsigned long attrib; + + attrib = xi_get_attrib( members[i] ); + if ( ( attrib & XI_ATR_ENABLED ) && + !( attrib & XI_ATR_SELECTABLE ) ) + { + have_column = TRUE; + break; + } + } + if ( !have_column ) + continue; + } + + /* If the tab key was pressed, and the focus is not on the first + * enabled and visible radio button in the group, then skip to a + * control that is not in the group. */ + { + XI_OBJ **rb_obj, + *parent; + int i; + + if ( c != XI_KEY_DOWN && + obj->type == XIT_BTN && + obj->v.btn->type == XIBT_RADIOBTN && + obj->parent->type == XIT_CONTAINER ) + { + parent = obj->parent; + for ( i = 0, rb_obj = parent->children; i < parent->nbr_children; ++i, + ++rb_obj ) + if ( ( xi_get_attrib( *rb_obj ) & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + break; + if ( *rb_obj != obj ) + continue; + } + } + + /* If a meta-tab key was pressed, and the obj->type == XIT_FORM then + * move the focus to the first field in the form */ + if ( obj->type == XIT_FORM ) + { + XI_OBJ **field_obj; + int i; + + for ( i = 0, field_obj = obj->children; i < obj->nbr_children; ++i, ++field_obj ) + if ( ( xi_get_attrib( *field_obj ) & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + break; + if ( i == obj->nbr_children ) + continue; + obj = *field_obj; + } + + break; + } + return ( obj ); + case XI_NEXT_FORM_BACKTAB: + case XI_NEXT_ITF_BACKTAB: + switch ( tab_type ) + { + case XI_NEXT_FORM_BACKTAB: + if ( type == XIT_FORM ) + return ( xi_search_itf( itf, XI_SEARCH_FOR_FIELD, 0 ) ); + obj = focus_obj; + break; + case XI_NEXT_ITF_BACKTAB: + obj = focus_obj->parent; + if ( obj->type == XIT_ITF ) /* No container, ignore it */ + return NULL; + break; + default: + break; + } + while ( TRUE ) + { + /* xi_search_itf, searching for TAB CID finds the tab control id just + * previous in the tabbing sequence, hence the break at the bottom of + * the loop. */ + obj = xi_search_itf( itf, XI_SEARCH_FOR_TAB_CID, obj->cid ); + if ( obj == NULL || obj == focus_obj ) + break; +#if XIWS == XIWS_MAC + if ( xi_get_native_controls( obj ) + && ( obj->type == XIT_BTN || obj->type == XIT_CONTAINER ) ) + continue; +#endif + if ( + ( xi_get_attrib( obj ) & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) != + ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + continue; + + if ( obj->type == XIT_LIST ) + { + int i, + nbr_members; + XI_OBJ **members; + BOOLEAN have_column; + + members = xi_get_member_list( obj, &nbr_members ); + have_column = FALSE; + for ( i = 0; i < nbr_members; ++i ) + { + unsigned long attrib; + + attrib = xi_get_attrib( members[i] ); + if ( ( attrib & XI_ATR_ENABLED ) && + !( attrib & XI_ATR_SELECTABLE ) ) + { + have_column = TRUE; + break; + } + } + if ( !have_column ) + continue; + } + + /* If a meta-tab key was pressed, and the obj->type == XIT_FORM then + * move the focus to the first field in the form */ + if ( obj->type == XIT_FORM ) + { + XI_OBJ **field_obj; + int i; + + for ( i = 0, field_obj = obj->children; i < obj->nbr_children; ++i, ++field_obj ) + if ( ( xi_get_attrib( *field_obj ) & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + break; + if ( i == obj->nbr_children ) + continue; + obj = *field_obj; + } + break; + } + if ( obj && c != XI_KEY_UP && + obj->type == XIT_BTN && + obj->v.btn->type == XIBT_RADIOBTN && + obj->parent->type == XIT_CONTAINER && + obj->parent->children[0] != obj ) + { + obj = obj->parent->children[0]; + while ( TRUE ) + { + if ( ( xi_get_attrib( obj ) & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) == ( XI_ATR_ENABLED + | XI_ATR_VISIBLE ) ) + break; + obj = xi_search_itf( itf, XI_SEARCH_FOR_TAB_CID, obj->cid ); + } + } + return ( obj ); + } + return NULL; +} + +void +xi_aga_field_set_caret_pos( XI_OBJ * xi_obj, int pos ) +{ + if ( xi_obj->type == XIT_FIELD ) + { + STX_DATA *stxp = ( STX_DATA * ) xi_obj->v.field->stx; + + xi_text_selection_set( stxp->xi_text, pos, pos ); + } +} +/* + xi_lowlevel_focus: inform a control that it is gaining or losing the focus. + A control may reset some internal state when this happens. + This is not refusable. +*/ +void +xi_lowlevel_focus( XI_OBJ * xi_obj, BOOLEAN set ) +{ + XI_OBJ *itf; + XinWindow win; + BOOLEAN native_controls = xi_get_native_controls( xi_obj ); + + itf = xi_obj->itf; + win = itf->v.itf->xin_win; + if ( native_controls ) + { + if ( set && xi_obj->type != XIT_BTN ) /* should be set, not ! set */ + if ( XinWindowFocusGet( ) == win ) /* should be ==, not != */ + XinWindowFocusSet( win ); + } + switch ( xi_obj->type ) + { + case XIT_CELL: + lm_focus_set( xi_obj->parent->v.list->lm, xi_obj->v.cell.row, + xi_obj->v.cell.column, xi_obj->v.cell.is_vert_scrolled, set ); + return; + case XIT_FIELD: + stx_focus_set( xi_obj->v.field->stx, set ); + break; + case XIT_BTN: + { + XI_BTN_DATA *bd; + + bd = xi_obj->v.btn; + if ( !native_controls ) + { + xi_invalidate_rect( win, &bd->rct ); + } + else + { + if ( set ) + XinWindowFocusSet( bd->btnctl ); + } + break; + } + default: + /* ignore */ + break; + } +} + +/* + is_group_member: given an object, determine if it is in a group. +*/ +static BOOLEAN +is_group_member( XI_OBJ * obj, XI_OBJ * group ) +{ + int *cidlist; + int i; + + cidlist = group->v.group->cidlist; + for ( i = group->v.group->nbr_cids; i > 0; i--, cidlist++ ) + { + if ( *cidlist == obj->cid ) + return ( TRUE ); + } + return ( FALSE ); +} + + +BOOLEAN +xi_is_focus_moving( XI_OBJ * xi_obj ) +{ + XI_OBJ *itf = xi_obj->itf; + + return itf->v.itf->moving_focus; +} + + +/* ----------------------------------------------------------------------- */ +/* lm_list_is_about_to_lose_focus */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +lm_list_is_about_to_lose_focus( LM_DATA * lmp ) +{ + if ( lm_focus_list_has( lmp ) && + ( lm_focus_state_get( lmp ) == LM_FOCUS_VERTICALLY_SCROLLED ) ) + { + lm_focus_create_temp_row( lmp ); + return TRUE; + } + return FALSE; +} + +/* ----------------------------------------------------------------------- */ +/* lm_list_did_lose_focus */ +/* ----------------------------------------------------------------------- */ +static void +lm_list_did_lose_focus( LM_DATA * lmp ) +{ + lm_focus_rec_free( lmp ); +} + + +/* ----------------------------------------------------------------------- */ +/* lm_list_did_not_lose_focus */ +/* ----------------------------------------------------------------------- */ +static void +lm_list_did_not_lose_focus( LM_DATA * lmp ) +{ + lm_allocate_rec_info( lmp, lmp->realized_rows_array_len - 1 ); + --lmp->nbr_realized_rows; + lm_focus_rec_set( lmp, lm_focus_rec_saved_get( lmp ) ); +} + +/* ----------------------------------------------------------------------- */ +/* send focus event */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +send_object_event( XI_OBJ * object, XI_EVENT_TYPE event_type ) +{ + XI_EVENT xiev; + + MEMCLEAR( xiev ); + xiev.type = event_type; + xiev.v.xi_obj = object; + call_cb( object->itf, &xiev ); + return !xiev.refused; +} + + +/* ----------------------------------------------------------------------- */ +/* move_focus_off_groups */ +/* ----------------------------------------------------------------------- */ + +static BOOLEAN +move_group_focus( XI_OBJ * primary_obj, XI_OBJ * secondary_obj, XI_OBJ * itf, + XI_EVENT_TYPE event_type, BOOLEAN primary_is_cell ) +{ + XI_OBJ **objp; + int i; + BOOLEAN moving_between_rows = FALSE; + + if ( primary_obj == NULL || (!primary_is_cell && !xi_is_obj( primary_obj, itf ))) + return TRUE; + if ( secondary_obj != NULL && secondary_obj->type == XIT_CELL ) + { + if ( primary_obj->type == XIT_CELL ) + moving_between_rows = ( primary_obj->v.cell.row + != secondary_obj->v.cell.row ); + secondary_obj = secondary_obj->parent->children[ + secondary_obj->v.cell.column]; + } + if ( primary_obj->type == XIT_CELL ) + primary_obj = primary_obj->parent->children[primary_obj->v.cell.column]; + objp = primary_obj->itf->children; + for ( i = primary_obj->itf->nbr_children; i > 0; i--, objp++ ) + { + XI_OBJ *obj; + + obj = *objp; + if ( obj->type == XIT_GROUP && is_group_member( primary_obj, obj ) && + ( secondary_obj == NULL || !is_group_member( secondary_obj, obj ) || + moving_between_rows ) ) + if ( !send_object_event( obj, event_type ) ) + return FALSE; + } + return TRUE; +} + +/* ----------------------------------------------------------------------- */ +/* move_off_column */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +move_off_column( XI_OBJ * old_focus, XI_OBJ * new_focus ) +{ + if ( new_focus != NULL && new_focus->type == XIT_CELL + && old_focus->v.cell.column == new_focus->v.cell.column ) + return TRUE; + old_focus = old_focus->parent->children[old_focus->v.cell.column]; + return send_object_event( old_focus, XIE_OFF_COLUMN ); +} + +/* ----------------------------------------------------------------------- */ +/* move_off_row */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +move_row_focus( XI_OBJ * primary_obj, XI_OBJ * secondary_obj, + XI_EVENT_TYPE event_type ) +{ + XI_OBJ row_obj; + + /* move off of row */ + if ( secondary_obj != NULL && secondary_obj->type == XIT_CELL + && primary_obj->v.cell.row == secondary_obj->v.cell.row + && primary_obj->parent == secondary_obj->parent ) + return TRUE; + XI_MAKE_ROW( &row_obj, primary_obj->parent, primary_obj->v.cell.row ); + row_obj.v.row_data.is_vert_scrolled = primary_obj->v.cell.is_vert_scrolled; + if ( !send_object_event( &row_obj, event_type ) ) + return FALSE; + return TRUE; +} + +/* ----------------------------------------------------------------------- */ +/* move_on_column */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +move_on_column( XI_OBJ * old_focus, XI_OBJ * new_focus ) +{ + if ( old_focus != NULL && old_focus->type == XIT_CELL + && old_focus->parent == new_focus->parent + && old_focus->v.cell.column == new_focus->v.cell.column ) + return TRUE; + new_focus = new_focus->parent->children[new_focus->v.cell.column]; + return send_object_event( new_focus, XIE_ON_COLUMN ); +} + +/* ----------------------------------------------------------------------- */ +/* same_parents */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +same_parents( XI_OBJ * one, XI_OBJ * two ) +{ + if ( one != NULL && one->type != XIT_LIST && one->type != XIT_FORM ) + one = one->parent; + if ( two != NULL && two->type != XIT_LIST && two->type != XIT_FORM ) + two = two->parent; + return one == two; +} + +/* ----------------------------------------------------------------------- */ +/* gen_remove_focus_events */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +gen_remove_focus_events( XI_OBJ * old_focus, XI_OBJ * new_focus ) +{ + XI_OBJ * itf; + BOOLEAN old_is_cell = (old_focus != NULL && old_focus->type == XIT_CELL); + /* move off old 1st-level object */ + if ( old_focus == NULL ) + return TRUE; + itf = old_focus->itf; + switch ( old_focus->type ) + { + case XIT_CELL: + if ( !send_object_event( old_focus, XIE_OFF_CELL ) + || !move_off_column( old_focus, new_focus ) + || !move_group_focus( old_focus, new_focus, itf, XIE_OFF_GROUP, old_is_cell ) + || !move_row_focus( old_focus, new_focus, XIE_OFF_ROW ) ) + return FALSE; + if ( !same_parents( old_focus, new_focus ) ) + return send_object_event( old_focus->parent, XIE_OFF_LIST ); + break; + case XIT_LIST: + return ( move_group_focus( old_focus, new_focus, itf, XIE_OFF_GROUP, old_is_cell ) + && ( same_parents( old_focus, new_focus ) + || send_object_event( old_focus, XIE_OFF_LIST ) ) ); + case XIT_FIELD: + if ( !send_object_event( old_focus, XIE_OFF_FIELD ) + || !move_group_focus( old_focus, new_focus, itf, XIE_OFF_GROUP, old_is_cell ) ) + return FALSE; + if ( xi_is_obj( old_focus, itf ) && old_focus->parent != new_focus->parent ) + return send_object_event( old_focus->parent, XIE_OFF_FORM ); + break; + default: + return move_group_focus( old_focus, new_focus, itf, XIE_OFF_GROUP, old_is_cell ); + } + return TRUE; +} + +/* ----------------------------------------------------------------------- */ +/* gen_place_focus_events */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +gen_place_focus_events( XI_OBJ * old_focus, XI_OBJ * new_focus, BOOLEAN old_is_cell ) +{ + XI_OBJ * itf; + if ( new_focus == NULL ) + return TRUE; + if ( old_focus != NULL ) + itf = old_focus->itf; + else + itf = new_focus->itf; + switch ( new_focus->type ) + { + case XIT_CELL: + if ( !same_parents( old_focus, new_focus ) + && !send_object_event( new_focus->parent, XIE_ON_LIST ) ) + return FALSE; + return ( move_row_focus( new_focus, old_focus, XIE_ON_ROW ) + && move_group_focus( new_focus, old_focus, itf, XIE_ON_GROUP, old_is_cell ) + && move_on_column( old_focus, new_focus ) + && send_object_event( new_focus, XIE_ON_CELL ) ); + case XIT_LIST: + return ( ( same_parents( old_focus, new_focus ) + || send_object_event( new_focus, XIE_ON_LIST ) ) + && move_group_focus( new_focus, old_focus, itf, XIE_ON_GROUP, old_is_cell ) ); + case XIT_FIELD: + if ( ( old_focus == NULL || new_focus->parent != old_focus->parent ) + && !send_object_event( new_focus->parent, XIE_ON_FORM ) ) + return FALSE; + return ( move_group_focus( new_focus, old_focus, itf, XIE_ON_GROUP, old_is_cell ) + && send_object_event( new_focus, XIE_ON_FIELD ) ); + default: + break; + } + return move_group_focus( new_focus, old_focus, itf, XIE_ON_GROUP, old_is_cell ); +} + +/* ----------------------------------------------------------------------- */ +/* find_cell_obj */ +/* ----------------------------------------------------------------------- */ +static XI_OBJ * +find_cell_obj( XI_OBJ * new_focus ) +{ + LM_DATA *lmp; + XI_OBJ tmp_obj; + XI_LIST_DATA *list_data; + + list_data = new_focus->parent->v.list; + lmp = ( LM_DATA * ) list_data->lm; + + tmp_obj = *new_focus; + + new_focus = get_non_focus_cell_obj( tmp_obj.parent->v.list ); + new_focus->v.cell.row = tmp_obj.v.cell.row; + new_focus->v.cell.column = tmp_obj.v.cell.column; + if ( new_focus->v.cell.row >= ( unsigned char ) lmp->nbr_realized_rows ) + return new_focus->itf; + return new_focus; +} + +/* ----------------------------------------------------------------------- */ +/* move_focus_to_list */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +move_focus_to_list( XI_OBJ ** focus_result ) +{ + LM_DATA *lmp; + int col; + XI_OBJ *new_focus; + XI_LIST_DATA *list_data; + int first_col; + int last_col; + int start_col; + + new_focus = *focus_result; + list_data = new_focus->v.list; + lmp = ( LM_DATA * ) list_data->lm; + if ( new_focus->nbr_children <= 0 ) + return FALSE; + if ( lmp->sizing_row ) + return FALSE; + if ( lmp->nbr_realized_rows == 0 ) + { + *focus_result = new_focus->itf; + return TRUE; + } + if ( lmp->single_select ) /* attempt to select row */ + return TRUE; + new_focus = list_data->focus_cell; + /* if cell is selectable, disabled, etc, then find another cell */ + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + start_col = new_focus->v.cell.column; + else + start_col = 0; + col = start_col; + lm_get_visible_columns( list_data->lm, &first_col, &last_col ); + while ( TRUE ) + { + long attrib; + + attrib = lmp->lm_column_data[col]->attrib; + if ( ( attrib & XI_ATR_ENABLED ) && !( attrib & XI_ATR_SELECTABLE ) + && ( col < lm_get_fixed_columns( list_data->lm ) + || (col >= first_col && col <= last_col ))) + { + new_focus->v.cell.column = ( unsigned char ) col; + break; + } + col++; + if ( col == lmp->nbr_columns ) + col = 0; + if ( col == start_col ) + { + *focus_result = new_focus->itf; + return TRUE; + } + } + if ( new_focus->v.cell.row >= ( unsigned char ) lmp->nbr_realized_rows ) + { + if ( new_focus->type == XIT_CELL ) + { + /* Last row had focus, but has been deleted. Set focus to new last row, + * if there is one */ + if ( lmp->nbr_realized_rows >= 1 ) + new_focus->v.cell.row = lmp->nbr_realized_rows - 1; + else + new_focus = xi_find_next_obj( new_focus->parent, XI_NEXT_FORM_TAB, + XI_PREF_FORM_TAB_CHAR ); + } + else + new_focus = new_focus->itf; + } + *focus_result = new_focus; + return TRUE; +} + +/* ----------------------------------------------------------------------- */ +/* determine_focus_button */ +/* ----------------------------------------------------------------------- */ +static XI_OBJ * +determine_focus_button( XI_OBJ * new_focus ) +{ + int i; + unsigned long attr = 0L; + + if ( !new_focus->nbr_children ) + XinError( 20005, XinSeverityFatal, 0L ); + for ( i = 0; i < new_focus->nbr_children; i++ ) + { + attr = xi_get_attrib( new_focus->children[i] ); + if ( ( attr & XI_ATR_ENABLED ) && ( attr & XI_ATR_VISIBLE ) ) + return new_focus->children[i]; + } + return xi_find_next_obj( new_focus, XI_NEXT_FORM_TAB, XI_PREF_FORM_TAB_CHAR ); +} + +/* ----------------------------------------------------------------------- */ +/* determine_new_focus */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +determine_new_focus( XI_OBJ ** new_focus ) +{ + if ( *new_focus == NULL ) + return TRUE; + do + { + switch ( ( *new_focus )->type ) + { + case XIT_CELL: + *new_focus = find_cell_obj( *new_focus ); + break; + case XIT_LIST: + return move_focus_to_list( new_focus ); + case XIT_FORM: + { + XI_OBJ *focus_field = ( *new_focus )->v.form->focus_field; + + if ( focus_field ) + *new_focus = focus_field; + break; + } + case XIT_CONTAINER: + *new_focus = determine_focus_button( *new_focus ); + break; + default: + break; + } + } while ( *new_focus != NULL && + ( ( *new_focus )->type == XIT_CONTAINER || + ( *new_focus )->type == XIT_FORM || + ( *new_focus )->type == XIT_LIST ) ); + if ( *new_focus == NULL ) + return FALSE; + return TRUE; +} + +/* ----------------------------------------------------------------------- */ +/* move_focus_internal */ +/* ----------------------------------------------------------------------- */ +static void +check_new_focus_enabled( XI_OBJ * xi_obj ) +{ + if ( xi_obj == NULL ) + return; + switch ( xi_obj->type ) + { + case XIT_CELL: + { + BOOLEAN xi_obj_enabled; + + xi_obj_enabled = ( ( xi_get_attrib( xi_obj->parent ) & ( XI_ATR_ENABLED | + XI_ATR_VISIBLE ) ) == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ); + if ( !xi_obj_enabled ) + XinError( 20006, XinSeverityFatal, 0L ); + break; + } + case XIT_BTN: + case XIT_FIELD: + case XIT_LIST: + { + BOOLEAN xi_obj_enabled; + + xi_obj_enabled = ( ( xi_get_attrib( xi_obj ) & ( XI_ATR_ENABLED | + XI_ATR_VISIBLE ) ) == ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ); + if ( !xi_obj_enabled ) + XinError( 20007, XinSeverityFatal, 0L ); + break; + } + default: + break; + } +} + +/* ----------------------------------------------------------------------- */ +/* move_focus_internal */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +determine_alternate_focus( XI_OBJ * old_focus, XI_OBJ ** new_focus, + XI_OBJ * itf, + BOOLEAN next_if_disabled, + int check_for_reenabled, BOOLEAN old_is_cell, + BOOLEAN new_is_cell) +{ + XI_OBJ *xi_obj; + + if (!new_is_cell && !xi_is_obj( *new_focus, itf )) + { /* Former new focus deleted. We're guessing, now. */ + if (!old_is_cell && !xi_is_obj( old_focus, itf )) + { /* Both objects deleted. Find first available obj in itf. */ + *new_focus = itf; + } else { + /* Find next obj from old_focus. */ + *new_focus = xi_find_next_obj( old_focus, XI_NEXT_FORM_TAB, XI_PREF_FORM_TAB_CHAR ); + } + } + xi_obj = *new_focus; + /* if field for new focus has been disabled, proceed with next field */ + if ( xi_obj->type != XIT_CELL && xi_obj->type != XIT_ITF ) + { + unsigned long attrib; + + attrib = xi_get_attrib( xi_obj ); + if ( !( attrib & XI_ATR_ENABLED ) ) + { + if ( next_if_disabled ) + xi_obj = xi_find_next_obj( xi_obj, XI_NEXT_FORM_TAB, + XI_PREF_FORM_TAB_CHAR ); + else + return FALSE; + } + } + + /* if next field used to be disabled, and is not enabled, move to it */ + if ( check_for_reenabled && (old_is_cell || xi_is_obj( old_focus, itf ))) + { + if ( xi_obj->type == XIT_FIELD ) + { + XI_OBJ *tmp_obj; + + tmp_obj = xi_find_next_obj( old_focus, + check_for_reenabled == 1 ? XI_NEXT_FORM_TAB : XI_NEXT_FORM_BACKTAB, + check_for_reenabled == 1 ? xi_get_pref( XI_PREF_FORM_TAB_CHAR ) : + xi_get_pref( XI_PREF_FORM_BACKTAB_CHAR ) ); + if ( tmp_obj ) + xi_obj = tmp_obj; + } + } + + if ( xi_obj->type == XIT_CELL ) + { + LM_DATA *lmp; + + lmp = (LM_DATA *)xi_obj->parent->v.list->lm; + if ( lmp->nbr_realized_rows == 0 ) + { + *new_focus = xi_obj->itf; + return TRUE; + } + else + { + if ( xi_obj->v.cell.row > lmp->nbr_realized_rows - 1 ) + xi_obj->v.cell.row = lmp->nbr_realized_rows - 1; + } + } + + *new_focus = xi_obj; + return TRUE; +} + +/* ----------------------------------------------------------------------- */ +/* perform_move_focus */ +/* ----------------------------------------------------------------------- */ +static BOOLEAN +perform_move_focus( XI_OBJ * old_focus, XI_OBJ * new_focus, + BOOLEAN make_callbacks, + BOOLEAN next_if_disabled, + int check_for_reenabled ) +{ + BOOLEAN draw_old_row; + BOOLEAN draw_new_row; + BOOLEAN old_is_cell = (old_focus != NULL && old_focus->type == XIT_CELL); + BOOLEAN new_is_cell; + XI_OBJ* itf; + + itf = new_focus->itf; + if ( !determine_new_focus( &new_focus ) ) + return FALSE; + check_new_focus_enabled( new_focus ); + /* remove focus */ + if ( make_callbacks && !gen_remove_focus_events( old_focus, new_focus ) ) + return FALSE; + new_is_cell = (new_focus != NULL && new_focus->type == XIT_CELL); + if ( !determine_alternate_focus( old_focus, &new_focus, itf, next_if_disabled, + check_for_reenabled, old_is_cell, new_is_cell ) ) + return FALSE; + if ( make_callbacks && !gen_place_focus_events( old_focus, new_focus, old_is_cell ) ) + return FALSE; + /* if list has focus, it's a single-select list */ + if ( new_focus != NULL && new_focus->type == XIT_LIST ) + { + unsigned long attrib; + XI_OBJ row_obj; + XI_LIST_DATA *list_data = new_focus->v.list; + LM_DATA *lmp = ( LM_DATA * ) list_data->lm; + int row = list_data->focus_cell->v.cell.row; + + /* See if the focus row is selected. */ + if ( row >= lmp->nbr_realized_rows ) + row = lmp->nbr_realized_rows - 1; + XI_MAKE_ROW( &row_obj, new_focus, row ); + attrib = xi_get_attrib( &row_obj ); + /* If it isn't, see if any row is selected. */ + if ( ( attrib & XI_ATR_SELECTED ) == 0 ) + { + for ( row = 0; row < lmp->nbr_realized_rows; row++ ) + { + XI_MAKE_ROW( &row_obj, new_focus, row ); + attrib = xi_get_attrib( &row_obj ); + if ( attrib & XI_ATR_SELECTED ) + break; + } + } + if ( row < lmp->nbr_realized_rows ) + /* Move the focus to the selected row. */ + list_data->focus_cell->v.cell.row = row; + else + { + /* Select the first row in the list and make it the focus row. */ + list_data->focus_cell->v.cell.row = 0; + XI_MAKE_ROW( &row_obj, new_focus, 0 ); + if ( make_callbacks && !list_data->in_select_process ) + { + XI_EVENT event; + + MEMCLEAR( event ); + event.type = XIE_SELECT; + event.v.select.xi_obj = &row_obj; + event.v.select.selected = TRUE; + event.v.select.records = lmp->recs; + event.v.select.dbl_click = FALSE; + call_cb( new_focus->itf, &event ); + if ( event.refused ) + return FALSE; + } +/* + xi_set_attrib(&row_obj, attrib | XI_ATR_SELECTED ); +*/ + } + } + + /* if we get to here then it has happened */ + { + XI_ITF_DATA *itf_data; + + itf_data = new_focus->itf->v.itf; + itf_data->chg_flag = FALSE; + itf_data->focus_obj = new_focus; + if ( itf_data->virtual_itf ) + xi_make_obj_visible( new_focus ); + } + if ( new_focus->type == XIT_CELL ) + new_focus->parent->v.list->focus_cell = new_focus; + if ( new_focus->type == XIT_FIELD ) + new_focus->parent->v.form->focus_field = new_focus; + if ( old_focus != NULL && (old_is_cell || xi_is_obj( old_focus, itf ))) + xi_lowlevel_focus( old_focus, FALSE ); + if ( new_focus != NULL ) + xi_lowlevel_focus( new_focus, TRUE ); + /* If the old_focus or the new_focus is a cell, and they're in different + * rows, redraw both rows. */ + draw_old_row = FALSE; + draw_new_row = FALSE; + if ( old_focus && old_is_cell ) + { + if ( new_focus && new_focus->type == XIT_CELL ) + { + if ( old_focus->parent != new_focus->parent || + old_focus->v.cell.row != new_focus->v.cell.row ) + { + draw_old_row = TRUE; + draw_new_row = TRUE; + } + } + else + draw_old_row = TRUE; + } + else + { + if ( new_focus && new_focus->type == XIT_CELL ) + draw_new_row = TRUE; + } + if ( draw_old_row ) + { + XI_LIST_DATA *list_data = old_focus->parent->v.list; + LM_DATA *lmp = ( LM_DATA * ) list_data->lm; + + if ( ( !lmp->button_on_cell_focus || lmp->row_focus_border ) && + old_focus->v.cell.is_vert_scrolled != TRUE && + (int)old_focus->v.cell.row < lmp->nbr_realized_rows ) + { + lm_focus_cell_invis_make( lmp ); + lm_redraw_row( ( LM_DATA * ) list_data->lm, old_focus->v.cell.row, FALSE ); + lm_focus_cell_visible_attempt( lmp ); + } + } + if ( draw_new_row ) + { + XI_LIST_DATA *list_data = new_focus->parent->v.list; + LM_DATA *lmp = ( LM_DATA * ) list_data->lm; + + if ( !lmp->button_on_cell_focus || lmp->row_focus_border ) + { + lm_focus_cell_invis_make( lmp ); + lm_redraw_row( lmp, new_focus->v.cell.row, FALSE ); + lm_focus_cell_visible_attempt( lmp ); + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + set_focus_cell_rct( lmp, new_focus->v.cell.row, new_focus->v.cell.column, FALSE ); + } + } + + if ( old_focus && (old_is_cell || xi_is_obj( old_focus, itf )) && new_focus ) + xi_draw_foc_and_dflt_if_necessary( old_focus, new_focus ); + return TRUE; +} + +/* ----------------------------------------------------------------------- */ +/* move_focus_internal */ +/* ----------------------------------------------------------------------- */ +/* + This function attempts to move the focus to the object indicated, + returning TRUE if successful, FALSE if refused. This function will + set or remove the focus from any low-level editing modules as necessary. + + If make_callbacks is TRUE, then XI callbacks will be issued to + determine whether the focus change should be allowed before proceeding. +*/ +BOOLEAN +xi_move_focus_internal( XI_OBJ * xi_obj, BOOLEAN make_callbacks, + BOOLEAN next_if_disabled, int check_for_reenabled ) +{ + XI_OBJ *focus_obj; + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + LM_DATA *lmp = NULL; + BOOLEAN focus_was_on_invisible = FALSE; + + itf = xi_obj->itf; + itf_data = xi_obj->itf->v.itf; + focus_obj = itf_data->focus_obj; + if ( xi_compare_objs( focus_obj, xi_obj ) ) + return ( TRUE ); + + if ( xi_obj->type == XIT_CELL ) + lm_calculate_pix_offsets( xi_obj->parent->v.list->lm ); + + itf_data->moving_focus = TRUE; + if ( focus_obj && focus_obj->type == XIT_CELL ) + { + XI_OBJ *list_obj; + + list_obj = focus_obj->parent; + lmp = ( LM_DATA * ) ( list_obj->v.list->lm ); + focus_was_on_invisible = lm_list_is_about_to_lose_focus( lmp ); + } + if ( !perform_move_focus( focus_obj, xi_obj, make_callbacks, next_if_disabled, + check_for_reenabled ) ) + { + itf_data->moving_focus = FALSE; + if ( focus_was_on_invisible ) + lm_list_did_not_lose_focus( lmp ); + if ( make_callbacks ) + { + XI_EVENT event; + + MEMCLEAR( event ); + event.type = XIE_POST_NAVIGATION; + call_cb( itf, &event ); + } + return FALSE; + } + itf_data->moving_focus = FALSE; + if ( focus_was_on_invisible ) + lm_list_did_lose_focus( lmp ); + if ( make_callbacks ) + { + XI_EVENT event; + + MEMCLEAR( event ); + event.type = XIE_POST_NAVIGATION; + call_cb( itf, &event ); + } + itf_data->moving_focus = FALSE; + return ( TRUE ); +} + +BOOLEAN +xi_move_focus( XI_OBJ * xi_obj ) +{ + if (xi_obj != NULL) + { + if ( xi_obj->type == XIT_ITF || xi_obj->type == XIT_CELL + || ( xi_get_attrib( xi_obj ) & XI_ATR_VISIBLE ) ) + { + if ( xi_obj->type == XIT_CELL ) + { + XI_OBJ *list_obj = xi_obj->parent; + LM_DATA *lmp = ( LM_DATA * ) ( list_obj->v.list->lm ); + if ( CELL_IS_SELECTABLE( ( LM ) lmp, xi_obj->v.cell.row, xi_obj->v.cell.column ) ) + return FALSE; + } + return xi_move_focus_internal( xi_obj, TRUE, FALSE, 0 ); + } + } + return FALSE; +} + +void +xi_set_focus( XI_OBJ * xi_obj ) +{ + if (xi_obj != NULL) + { + if ( xi_obj->type == XIT_ITF || xi_obj->type == XIT_CELL + || ( xi_get_attrib( xi_obj ) & XI_ATR_VISIBLE ) ) + { + if ( xi_obj->type == XIT_CELL ) + { + XI_OBJ *list_obj = xi_obj->parent; + LM_DATA *lmp = ( LM_DATA * ) ( list_obj->v.list->lm ); + if ( CELL_IS_SELECTABLE( ( LM ) lmp, xi_obj->v.cell.row, xi_obj->v.cell.column ) ) + return; + } + xi_move_focus_internal( xi_obj, FALSE, FALSE, 0 ); + } + } +} + +static void +xi_add_to_parent_list( XI_OBJ * obj, int position ) +{ + XI_OBJ *parent; + + if ( ( parent = obj->parent ) == NULL ) + return; + realloc_ptrs( ( void *** ) &parent->children, + parent->nbr_children, parent ); + if ( position == -1 ) + parent->children[parent->nbr_children] = obj; + else + { + int i; + + for ( i = parent->nbr_children; i > position; --i ) + parent->children[i] = parent->children[i - 1]; + parent->children[position] = obj; + } + parent->nbr_children++; +} + +static void +xi_stx_cb( STX_CB_DATA * stx_cb_data ) +{ + XI_EVENT xiev; + BOOLEAN send_cb = FALSE; + XI_OBJ *xi_obj; + + xi_obj = xiev.v.xi_obj = ( XI_OBJ * ) stx_get_app_data( stx_cb_data->stx ); + xiev.refused = FALSE; + switch ( stx_cb_data->cb_type ) + { + case STX_CB_CHAR: + /* generate an XIE_CHAR_FIELD */ + xiev.type = XIE_CHAR_FIELD; + xiev.v.chr.xi_obj = xi_obj; + xiev.v.chr.ch = stx_cb_data->v.chr.ch; + xiev.v.chr.shift = stx_cb_data->v.chr.shift; + xiev.v.chr.control = stx_cb_data->v.chr.control; + xiev.v.chr.alt = stx_cb_data->v.chr.alt; + xiev.v.chr.is_paste = stx_cb_data->v.chr.is_paste; + send_cb = TRUE; + break; + case STX_CB_CHANGE: + /* generate an XIE_CHG_FIELD */ + xiev.type = XIE_CHG_FIELD; + send_cb = TRUE; + break; + case STX_CB_FOCUS: + stx_cb_data->v.refused = !xi_move_focus_internal( xi_obj, TRUE, + TRUE, 0 ); + send_cb = FALSE; + break; + case STX_CB_DBL: + xiev.type = XIE_DBL_FIELD; + send_cb = TRUE; + break; + default: + XinError( 20008, XinSeverityFatal, 0L ); + } + if ( send_cb ) + call_cb( xi_obj->itf, &xiev ); + if ( stx_cb_data->cb_type == STX_CB_CHAR ) + { + stx_cb_data->v.chr.ch = xiev.v.chr.ch; + stx_cb_data->v.chr.refused = xiev.refused; + } +} + +static void +xi_lm_cb( LM_CB_DATA * lm_cb_data ) +{ + XI_EVENT xiev; + BOOLEAN send_cb = FALSE; + XI_OBJ *lm_obj; + XI_OBJ *next_obj; + XI_LIST_DATA *ldata; + LM_DATA *lmp; + + XI_OBJ row_obj; // AGA: dichiarato oggetto locale di cui altrimenti si perde traccia nell'evento! + + MEMCLEAR( xiev ); + lm_obj = ( XI_OBJ * ) lm_get_list_obj( lm_cb_data->lm ); + lmp = ( LM_DATA * ) lm_obj->v.list->lm; + ldata = lm_obj->v.list; + xiev.v.xi_obj = ldata->focus_cell; + + next_obj = get_non_focus_cell_obj( ldata ); + switch ( lm_cb_data->cb_type ) + { + case LM_CB_CHAR: + /* generate an XIE_CHAR_CELL */ + xiev.type = XIE_CHAR_CELL; + xiev.v.chr.xi_obj = ldata->focus_cell; + xiev.v.chr.ch = lm_cb_data->v.chr.ch; + xiev.v.chr.shift = lm_cb_data->v.chr.shift; + xiev.v.chr.control = lm_cb_data->v.chr.control; + xiev.v.chr.alt = lm_cb_data->v.chr.alt; + xiev.v.chr.is_paste = lm_cb_data->v.chr.is_paste; + send_cb = TRUE; + break; + case LM_CB_CHANGE: + xiev.type = XIE_CHG_CELL; + send_cb = TRUE; + break; + case LM_CB_FOCUS: + case LM_CB_CELL_BTN: + { + BOOLEAN ref; + XI_OBJ *focus_obj; + + focus_obj = xi_get_focus( lm_obj->itf ); + next_obj->v.cell.row = ( unsigned char ) lm_cb_data->row; + next_obj->v.cell.column = ( unsigned char ) lm_cb_data->column; + next_obj->v.cell.is_vert_scrolled = FALSE; + ref = FALSE; + + if ( focus_obj && focus_obj->type == XIT_CELL && next_obj->type == XIT_CELL ) + { + if ( focus_obj->parent != next_obj->parent || + focus_obj->v.cell.row != next_obj->v.cell.row || + focus_obj->v.cell.column != next_obj->v.cell.column ) + { + if ( !xi_move_focus_internal( next_obj, TRUE, FALSE, 0 ) ) + if ( lm_cb_data->cb_type == LM_CB_FOCUS ) + ref = lm_cb_data->v.refused = TRUE; + } + } + else if ( !xi_move_focus_internal( next_obj, TRUE, FALSE, 0 ) ) + if ( lm_cb_data->cb_type == LM_CB_FOCUS ) + ref = lm_cb_data->v.refused = TRUE; + next_obj = get_non_focus_cell_obj( ldata ); + next_obj->v.cell.row = ( unsigned char ) ( lm_cb_data->row ); + next_obj->v.cell.column = ( unsigned char ) ( lm_cb_data->column ); + send_cb = FALSE; + if ( ( !ref ) && ( lm_cb_data->cb_type == LM_CB_CELL_BTN ) ) + { + xiev.type = XIE_BUTTON; + xiev.v.xi_obj = next_obj; + send_cb = TRUE; + } + break; + } + case LM_CB_DBL: + xiev.type = XIE_DBL_CELL; + xiev.v.xi_obj->v.cell.row = ( unsigned char ) ( lm_cb_data->row ); + xiev.v.xi_obj->v.cell.column = ( unsigned char ) ( lm_cb_data->column ); + send_cb = TRUE; + break; + case LM_CB_TEXT: + xiev.type = XIE_CELL_REQUEST; + xiev.v.cell_request.list = lm_obj; + xiev.v.cell_request.s = lm_cb_data->v.text.text; + xiev.v.cell_request.len = lm_cb_data->v.text.len; + xiev.v.cell_request.col_nbr = lm_cb_data->column; + xiev.v.cell_request.rec = lm_cb_data->rec; + xiev.v.cell_request.icon_rid = lm_cb_data->v.text.icon_rid; + xiev.v.cell_request.bitmap = lm_cb_data->v.text.bitmap; + xiev.v.cell_request.attrib = lm_cb_data->v.text.attrib; + xiev.v.cell_request.color = lm_cb_data->v.text.color; + xiev.v.cell_request.back_color = lm_cb_data->v.text.back_color; + xiev.v.cell_request.records = lmp->recs; + send_cb = TRUE; + break; + case LM_CB_REC_ALLOCATE: + xiev.type = XIE_REC_ALLOCATE; + xiev.v.rec_allocate.list = lm_obj; + xiev.v.rec_allocate.record = lm_cb_data->v.rec_allocate.record; + send_cb = TRUE; + break; + case LM_CB_REC_FREE: + xiev.type = XIE_REC_FREE; + xiev.v.rec_free.list = lm_obj; + xiev.v.rec_free.record = lm_cb_data->v.rec_free.record; + send_cb = TRUE; + break; + case LM_CB_GET_FIRST: + case LM_CB_GET_NEXT: + case LM_CB_GET_PREV: + case LM_CB_GET_LAST: + switch ( lm_cb_data->cb_type ) + { + case LM_CB_GET_FIRST: + xiev.type = XIE_GET_FIRST; + break; + case LM_CB_GET_NEXT: + xiev.type = XIE_GET_NEXT; + break; + case LM_CB_GET_PREV: + xiev.type = XIE_GET_PREV; + break; + case LM_CB_GET_LAST: + xiev.type = XIE_GET_LAST; + break; + default: + break; + } + xiev.v.rec_request.list = lm_obj; + xiev.v.rec_request.spec_rec = lm_cb_data->v.rec_request.spec_rec; + xiev.v.rec_request.data_rec = lm_cb_data->v.rec_request.data_rec; + xiev.v.rec_request.percent = lm_cb_data->v.rec_request.percent; + xiev.v.rec_request.attrib = lm_cb_data->v.rec_request.attrib; + xiev.v.rec_request.color = lm_cb_data->v.rec_request.color; + send_cb = TRUE; + break; + case LM_CB_GET_PERCENT: + xiev.type = XIE_GET_PERCENT; + xiev.v.get_percent.list = lm_obj; + xiev.v.get_percent.record = lm_cb_data->v.get_percent.record; + send_cb = TRUE; + break; + case LM_CB_SELECT: + { + if ( lm_cb_data->row == 255 && lm_cb_data->column == 255 ) + { + xiev.type = XIE_SELECT; + xiev.v.select.xi_obj = lm_obj; + xiev.v.select.selected = TRUE; + xiev.v.select.dbl_click = FALSE; + xiev.v.select.shift = lm_cb_data->v.select.shift; + xiev.v.select.control = lm_cb_data->v.select.control; + xiev.v.select.records = lmp->recs; + xiev.v.select.column = 0; + send_cb = TRUE; + } + else if ( lm_cb_data->row == 255 ) + { + xiev.type = XIE_SELECT; + xiev.v.select.xi_obj = + lm_obj->children[lm_cb_data->column]; + xiev.v.select.selected = lm_cb_data->v.select.selected; + xiev.v.select.dbl_click = lm_cb_data->v.select.dbl_click; + xiev.v.select.shift = lm_cb_data->v.select.shift; + xiev.v.select.control = lm_cb_data->v.select.control; + xiev.v.select.column = lm_cb_data->column; + xiev.v.select.records = lmp->recs; + send_cb = TRUE; + } + else + { +// XI_OBJ row_obj; AGA was here + XI_MAKE_ROW( &row_obj, lm_obj, lm_cb_data->row ); + + xiev.type = XIE_SELECT; + xiev.v.select.xi_obj = &row_obj; + xiev.v.select.selected = lm_cb_data->v.select.selected; + xiev.v.select.dbl_click = lm_cb_data->v.select.dbl_click; + xiev.v.select.shift = lm_cb_data->v.select.shift; + xiev.v.select.control = lm_cb_data->v.select.control; + xiev.v.select.column = lm_cb_data->column; + xiev.v.select.records = lmp->recs; + send_cb = TRUE; + } + break; + } + case LM_CB_ROW_SIZE: + { + // XI_OBJ row_obj; AGA was here + + XI_MAKE_ROW( &row_obj, lm_obj, lm_cb_data->row ); + xiev.type = XIE_ROW_SIZE; + xiev.v.row_size.xi_obj = &row_obj; + xiev.v.row_size.new_row_height = lm_cb_data->v.row_size.new_row_height; + send_cb = TRUE; + break; + } + case LM_CB_COL_DELETE: + xiev.type = XIE_COL_DELETE; + xiev.v.column.list = lm_obj; + xiev.v.column.col_nbr = lm_cb_data->column; + send_cb = TRUE; + break; + case LM_CB_COL_MOVE: + xiev.type = XIE_COL_MOVE; + xiev.v.column.list = lm_obj; + xiev.v.column.col_nbr = lm_cb_data->column; + xiev.v.column.new_col_nbr = lm_cb_data->v.column.new_col_nbr; + xiev.v.column.in_fixed = lm_cb_data->v.column.in_fixed; + send_cb = TRUE; + break; + case LM_CB_COL_SIZE: + xiev.type = XIE_COL_SIZE; + xiev.v.column.list = lm_obj; + xiev.v.column.col_nbr = lm_cb_data->column; + xiev.v.column.new_col_width = lm_cb_data->v.column.new_col_width; + xiev.v.column.new_col_pixel_width = + lm_cb_data->v.column.new_col_pixel_width; + send_cb = TRUE; + break; + case LM_CB_DROP_ROW: + xiev.type = XIE_DROP_ROW; + xiev.v.drop_row.src_list = lm_cb_data->v.drop_row.src_list; + xiev.v.drop_row.dest_list = lm_obj; + xiev.v.drop_row.src_rec = lm_cb_data->v.drop_row.src_rec; + xiev.v.drop_row.after_all_rows = lm_cb_data->v.drop_row.after_all_rows; + xiev.v.drop_row.delete_row = lm_cb_data->v.drop_row.delete_row; + if ( xiev.v.drop_row.after_all_rows || xiev.v.drop_row.delete_row ) + xiev.v.drop_row.dest_rec = 0; + else + xiev.v.drop_row.dest_rec = lmp->recs[lm_cb_data->row]; + xiev.v.drop_row.shift = lm_cb_data->v.drop_row.shift; + xiev.v.drop_row.control = lm_cb_data->v.drop_row.control; + send_cb = TRUE; + break; + default: + XinError( 20009, XinSeverityFatal, 0L ); + } + if ( send_cb ) + call_cb( lm_obj->itf, &xiev ); + if ( lm_cb_data->cb_type == LM_CB_CHAR ) + { + lm_cb_data->v.chr.refused = xiev.refused; + lm_cb_data->v.chr.ch = xiev.v.chr.ch; + } + if ( lm_cb_data->cb_type == LM_CB_SELECT ) + lm_cb_data->v.select.refused = xiev.refused; + if ( lm_cb_data->cb_type == LM_CB_ROW_SIZE ) + lm_cb_data->v.row_size.refused = xiev.refused; + if ( lm_cb_data->cb_type == LM_CB_TEXT ) + { + lm_cb_data->v.text.text = xiev.v.cell_request.s; + lm_cb_data->v.text.len = xiev.v.cell_request.len; + lm_cb_data->v.text.icon_rid = xiev.v.cell_request.icon_rid; + lm_cb_data->v.text.bitmap = xiev.v.cell_request.bitmap; + lm_cb_data->v.text.attrib = xiev.v.cell_request.attrib; + lm_cb_data->v.text.color = xiev.v.cell_request.color; + lm_cb_data->v.text.back_color = xiev.v.cell_request.back_color; + lm_cb_data->v.text.font = xiev.v.cell_request.font; + lm_cb_data->v.text.font_id = xiev.v.cell_request.font_id; + lm_cb_data->v.text.button = xiev.v.cell_request.button; + lm_cb_data->v.text.button_on_left = xiev.v.cell_request.button_on_left; + lm_cb_data->v.text.button_on_focus = xiev.v.cell_request.button_on_focus; + lm_cb_data->v.text.button_full_cell = xiev.v.cell_request.button_full_cell; + lm_cb_data->v.text.button_icon_rid = xiev.v.cell_request.button_icon_rid; + lm_cb_data->v.text.button_bitmap = xiev.v.cell_request.button_bitmap; + } + if ( lm_cb_data->cb_type == LM_CB_GET_PERCENT ) + lm_cb_data->v.get_percent.percent = xiev.v.get_percent.percent; + if ( lm_cb_data->cb_type == LM_CB_REC_ALLOCATE ) + lm_cb_data->v.rec_allocate.record = xiev.v.rec_allocate.record; + + switch ( lm_cb_data->cb_type ) + { + case LM_CB_GET_FIRST: + case LM_CB_GET_NEXT: + case LM_CB_GET_PREV: + case LM_CB_GET_LAST: + lm_cb_data->v.rec_request.data_rec = xiev.v.rec_request.data_rec; + lm_cb_data->v.rec_request.attrib = xiev.v.rec_request.attrib; + lm_cb_data->v.rec_request.color = xiev.v.rec_request.color; + lm_cb_data->v.rec_request.row_height = xiev.v.rec_request.row_height; + lm_cb_data->v.rec_request.refused = xiev.refused; + lm_cb_data->v.rec_request.has_focus = xiev.v.rec_request.has_focus; + break; + case LM_CB_COL_DELETE: + case LM_CB_COL_MOVE: + case LM_CB_COL_SIZE: + lm_cb_data->v.column.refused = xiev.refused; + break; + default: + break; + } +} + +/* + This queue is more of a stack than a queue but event ordering + is not important. This function is used to queue up events for + later processing to avoid recursive callbacks at bad times. + + For example, XIE_INIT is queued up during interface creation. +*/ +static void +xi_enqueue( XI_EVENT * xiev, XI_OBJ * itf ) +{ + XI_EQ *xi_el; + + xi_el = ( XI_EQ * ) xi_tree_malloc( sizeof( XI_EQ ), NULL ); + xi_el->xiev = *xiev; + xi_el->itf = itf; + xi_el->next = NULL; + if ( xi_eq == NULL ) + xi_eq = xi_el; + else + { + XI_EQ *last = xi_eq; + + while ( last->next != NULL ) + last = last->next; + last->next = xi_el; + } +} + +/* ------------------------------------------------------------------------- */ +/* remove all events associated with an interface from the que */ +/* ------------------------------------------------------------------------- */ + +static void +xi_que_remove( XI_OBJ * itf ) +{ + XI_EQ *current; + XI_EQ *last; + + last = NULL; + current = xi_eq; + while ( current != NULL ) + { + if ( current->itf != itf ) + { + last = current; + current = current->next; + } + else + { + XI_EQ *next = current->next; + + if ( last == NULL ) + xi_eq = next; + else + last->next = next; + xi_tree_free( current ); + current = next; + } + } +} + +/* + This function will dequeue all events queued up via xi_enqueue. + This function is called at the end of xi_event, so that any + events that were queued would be flushed out at that time. +*/ +void +xi_dequeue( void ) +{ + XI_EQ* old_eq; + XI_EQ *xi_el; + XI_OBJ **objp; + XI_OBJ *editable; + int i; + + old_eq = xi_eq; + xi_eq = NULL; + while ( old_eq != NULL ) + { + xi_el = old_eq; + + call_cb( xi_el->itf, &xi_el->xiev ); + old_eq = old_eq->next; + if ( xi_el->xiev.type == XIE_INIT ) + { + if (!xi_is_itf( xi_el->itf )) + return; + /* fill in all lists */ + for ( objp = xi_el->itf->children, i = xi_el->itf->nbr_children; + i != 0; i--, objp++ ) + { + if ( ( *objp )->type == XIT_LIST ) + { + if ( !( *objp )->v.list->done_initial_xi_scroll ) + { + if ( xi_get_attrib( *objp ) & XI_ATR_VISIBLE ) + { + ( *objp )->v.list->done_initial_xi_scroll = TRUE; + xi_scroll_internal( *objp, XI_SCROLL_FIRST, + ( *objp )->v.list->start_percent, FALSE ); + } + } + } + } + editable = xi_search_itf( xi_el->itf, XI_SEARCH_FOR_INITIAL, 0 ); + if ( xi_el->itf->v.itf->needs_update ) + { + xi_el->itf->v.itf->needs_update = FALSE; + XinWindowRectInvalidate( xi_get_window( xi_el->itf ), NULL ); + } + if ( editable ) + xi_move_focus_internal( editable, TRUE, FALSE, 0 ); + xi_tree_free( xi_el ); + } + } +} + +/* + xi_add_window_to_list: Record a window as being an XI window, + so that XI can tell its windows apart from other windows. +*/ +void +xi_add_window_to_list( XinWindow win, XI_OBJ * itf ) +{ + XI_WINDOW_LIST *list; + + /* list_parent is the tree memory parent of all structures in the linked list + * of windows. It is used to avoid clogging up the FIRSTNODE's child list + * too much. */ + if ( list_parent == NULL ) + list_parent = ( char * ) xi_tree_malloc( 1, NULL ); + list = ( XI_WINDOW_LIST * ) xi_tree_malloc( sizeof( XI_WINDOW_LIST ), list_parent ); + list->next = xi_window_list; + list->win = win; + list->itf = itf; + xi_window_list = list; +} + +void +xi_remove_window_from_list( XinWindow win ) +{ + XI_WINDOW_LIST *list; + XI_WINDOW_LIST *next; + + if ( win == xi_window_list->win ) + { + list = xi_window_list; + xi_window_list = xi_window_list->next; + xi_que_remove( list->itf ); + xi_tree_free( list ); + if ( xi_window_list == NULL ) + { + xi_tree_free( list_parent ); + list_parent = NULL; + } + return; + } + else + { + for ( list = xi_window_list; + list != NULL && ( next = list->next ) != NULL; + list = next ) + { + if ( next->win == win ) + { + list->next = next->next; + xi_que_remove( next->itf ); + xi_tree_free( next ); + return; + } + } + } + XinError( 20004, XinSeverityFatal, 0L ); +} + +/* find an interface from its id */ +XI_OBJ * +xi_get_itf_from_id( int id ) +{ + XI_WINDOW_LIST *list; + + list = xi_window_list; + while ( list != NULL && list->itf->cid != id ) + list = list->next; + if ( list == NULL ) + return NULL; + return list->itf; +} + +BOOLEAN +xi_is_window( XinWindow win ) +{ + register XI_WINDOW_LIST *list; + + for ( list = xi_window_list; list != NULL; list = list->next ) + if ( list->win == win ) + return TRUE; + return FALSE; +} + +BOOLEAN +xi_is_itf( XI_OBJ * itf ) +{ + register XI_WINDOW_LIST *list; + + for ( list = xi_window_list; list != NULL; list = list->next ) + if ( list->itf == itf ) + return TRUE; + return FALSE; +} + +XI_OBJ * +xi_get_itf_containing( XinPoint * pt ) +{ + register XI_WINDOW_LIST *list; + + for ( list = xi_window_list; list != NULL; list = list->next ) + { + XinRect rct; + + XinWindowRectOuterGet( list->win, &rct ); + if ( XinRectPointContained( &rct, pt ) ) + return list->itf; + } + return NULL; +} + +BOOLEAN +xi_is_changed( XI_OBJ * obj ) +{ + return obj->itf->v.itf->chg_flag; +} + +XI_OBJ * +xi_get_itf( XinWindow win ) +{ + XI_WINDOW_LIST *next; + + for ( next = xi_window_list; next != NULL; next = next->next ) + if ( next->win == win ) + { + return next->itf; + } + return NULL; +} + +BOOLEAN +xi_itf_closing_is( XI_OBJ * itf ) +{ + if ( itf == NULL || itf->type != XIT_ITF ) + XinError( 20039, XinSeverityFatal, 0L ); + return itf->v.itf->closing; +} + +BOOLEAN +xi_itf_in_event_destroy( XI_OBJ * itf ) +{ + if (itf == NULL || itf->type != XIT_ITF ) + XinError( 20039, XinSeverityFatal, 0L ); + return itf->v.itf->in_event_destroy; +} + +/* ------------------------------------------------------------------------ */ +/* create_children */ +/* ------------------------------------------------------------------------ */ +static void +create_children( XI_OBJ_DEF * xi_obj_def, XI_OBJ * obj, + BOOLEAN creating_list ) +{ + XI_OBJ_DEF **child; + int i; + + /* create children of the object if there are any */ + child = xi_obj_def->children; + for ( i = 0; i < xi_obj_def->nbr_children; child++, i++ ) + /* xi_create automatically adds object to the parent list */ + xi_create_internal( obj, *child, creating_list, FALSE ); +} + +/* ------------------------------------------------------------------------ */ +/* create_interface */ +/* ------------------------------------------------------------------------ */ +static void +interface_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * itf ) +{ + static BOOLEAN first_itf = TRUE; + XI_ITF_DATA *itf_data; + XI_ITF_DEF *itf_def; + XinRect def_rct; + XinRect *rctp; + XinRect rct; + XinWindow itf_win; + XinWindow parent = XinWindowTaskGet( ); + BOOLEAN do_move_window = FALSE; + XI_EVENT xiev; + + itf_def = xi_obj_def->v.itf; + rctp = itf_def->rctp; + xi_get_def_rect( xi_obj_def, &def_rct ); + def_rct.left = 12; + def_rct.right += 12; + if ( rctp == NULL || rctp->top == rctp->bottom ) + { + rct = def_rct; + if ( rctp ) + xi_offset_rect( &rct, rctp->left, rctp->top ); + } + else + rct = *rctp; + itf_data = ( XI_ITF_DATA * ) xi_tree_malloc( sizeof( XI_ITF_DATA ), + ( char * ) itf ); + itf_data->xi_eh = itf_def->xi_eh; + itf_data->half_baked = TRUE; + itf_data->edit_menu = itf_def->edit_menu; + itf_data->back_color = itf_def->back_color; + itf_data->automatic_back_color = itf_def->automatic_back_color; + if ( itf_def->automatic_back_color ) + { + if ( xi_get_pref( XI_PREF_3D_LOOK ) ) + itf_data->back_color = XI_COLOR_LTGRAY; + else + itf_data->back_color = XI_COLOR_WHITE; + } + itf_data->virtual_itf = itf_def->virtual_itf; + itf_data->modal = itf_def->modal; + itf_data->size_font_to_win = itf_def->size_font_to_win; + itf_data->tab_on_enter = itf_def->tab_on_enter; + itf_data->prev_modal = XI_NULL_WINDOW; + itf_data->bitmap = xi_bitmap_copy( itf_def->bitmap ); + itf_data->modal_wait = itf_def->modal_wait; + itf->v.itf = itf_data; + itf_data->use_xil_win = itf_def->use_xil_win; + itf_data->dequeue = XI_DEQUEUE_INIT; + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + if ( itf_def->font ) + XinFontCopy( &itf_data->font, itf_def->font ); + } +#ifdef XI_USE_XVT + else + { + if ( itf_def->font_id ) + itf_data->font = XinFontXvtConvert( itf_def->font_id ); + } +#endif + itf_data->fu_height = xi_get_fu_height_font( + itf_data->font ? itf_data->font : xi_get_system_font( ) ); + itf_data->fu_width = xi_get_fu_width_font( + itf_data->font ? itf_data->font : xi_get_system_font( ) ); + itf_data->max_xi_pnt.h = def_rct.right - def_rct.left; + itf_data->max_xi_pnt.v = def_rct.bottom - def_rct.top; + xi_pu_to_fu( itf->itf, &itf_data->max_xi_pnt, 1 ); + xi_even_fu_pnt( &itf_data->max_xi_pnt ); + + itf_data->menu_win = itf_def->menu_win; + itf_data->initial_focus_cid = itf_def->initial_focus_cid; + if ( itf_def->win ) + { +#ifdef XI_USE_XVT + if ( !( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + XinXvtWindowRegister( itf_def->win, xi_event ); +#endif + itf_data->xin_win = itf_def->win; + itf_win = itf_def->win; + if ( itf_def->size_win ) + do_move_window = TRUE; + XinWindowRectGet( itf_win, &itf_data->original_win_rct ); + if ( itf_data->font ) + itf_data->original_font_size = ( int ) XinFontSizeGet( itf_data->font ); + xi_add_window_to_list( itf_data->xin_win, itf ); + if ( xi_get_pref( XI_PREF_USE_APP_DATA ) ) + XinWindowAppDataSet( itf_data->xin_win, ( long ) ( itf ) ); + if ( itf_data->virtual_itf ) + { + xi_adjust_sb_vir_itf( itf_win, itf ); + XinScrollBarSet( itf_data->xin_win, XinScrollBarTypeHorizontal, + 0, 100, 1, 0 ); + XinScrollBarSet( itf_data->xin_win, XinScrollBarTypeVertical, + 0, 100, 1, 0 ); + } + first_itf = FALSE; + xi_add_to_parent_list( itf, -1 ); + XinCoalesceInvalidates( itf_win, TRUE ); + create_children( xi_obj_def, itf, FALSE ); + /* queue up initialization event */ + itf_data->needs_update = TRUE; + xiev.type = XIE_INIT; + xiev.v.xi_obj = itf; + xi_enqueue( &xiev, itf ); + itf_data->dequeue = XI_DEQUEUE_CALL; + + XinCoalesceInvalidates( itf_win, FALSE ); + if ( do_move_window ) + XinWindowRectSet( itf_win, &rct ); + } + else + { + XinWindowType win_type; + + win_type = XinWindowTypeDocument; + if ( rct.top < xi_get_pref( XI_PREF_ITF_MIN_TOP ) ) + { + int delta; + + delta = ( int ) xi_get_pref( XI_PREF_ITF_MIN_TOP ) - rct.top; + rct.top += delta; + rct.bottom += delta; + } + if ( rct.left < xi_get_pref( XI_PREF_ITF_MIN_LEFT ) ) + { + int delta; + + delta = ( int ) xi_get_pref( XI_PREF_ITF_MIN_LEFT ) - rct.left; + rct.left += delta; + rct.right += delta; + } + { + XinWindowDef Def; + + MEMCLEAR( Def ); + Def.parent = itf_def->parent != NULL ? itf_def->parent : parent; + Def.type = win_type; + Def.p_rect = &rct; + Def.title = itf_def->title; + Def.border_style = itf_def->border_style_set ? itf_def->border_style : + ( itf_def->ctl_size ? XinBorderSizable : XinBorderFixed ); + Def.vertical_scroll_bar = itf_def->ctl_vscroll; + Def.horizontal_scroll_bar = itf_def->ctl_hscroll; + Def.close_button = itf_def->ctl_close; + Def.iconized = itf_def->ctl_iconized; + Def.iconizable = itf_def->ctl_iconizable; + Def.visible = itf_def->visible; + Def.enabled = itf_def->enabled; + Def.back_color = XI_COLOR_WHITE; /* Special color for XM? */ + Def.menu_bar_rid = itf_def->menu_bar_rid; + Def.menu = itf_def->menu; + Def.eh = ( XinWindowEventHandler ) xi_event; + Def.maximized = itf_def->maximized; + Def.icon_rid = itf_def->icon_rid; + xi_creating_itf = itf; + interface_create_data.itf = itf; + interface_create_data.rct = rct; + interface_create_data.obj_def = xi_obj_def; + if ( itf_def->modal_wait ) + { + Def.mode = XinModalWait; + xi_in_modal_wait_create = TRUE; + } + else if ( itf_def->modal ) + Def.mode = XinModalReturn; + else if ( itf_def->autoclose ) + Def.mode = XinModalAutoclose; + else + Def.mode = XinModeless; + XinWindowCreate( &Def ); + itf_data->dequeue = XI_DEQUEUE_CALL; + xi_in_modal_wait_create = FALSE; + return; + } + } +} + +/* ------------------------------------------------------------------------ */ +/* xi_finish_interface_create() */ +/* do post-XinWindowCreate stuff. */ +/* ------------------------------------------------------------------------ */ +void +xi_finish_interface_create( XinWindow win ) +{ + XI_ITF_DATA *itf_data; + XinRect rct; + XinWindow itf_win; + XI_EVENT xiev; + XI_OBJ_DEF *xi_obj_def; + XI_OBJ *itf; + + if ( xi_creating_itf == NULL ) + return; + + xi_in_modal_wait_create = FALSE; + itf = interface_create_data.itf; + itf_data = itf->v.itf; + rct = interface_create_data.rct; + itf_win = win; + xi_obj_def = interface_create_data.obj_def; + + itf_data->xin_win = win; + itf_data->win_xi_pnt.v = rct.bottom - rct.top; + itf_data->win_xi_pnt.h = rct.right - rct.left; + xi_pu_to_fu( itf->itf, &itf_data->win_xi_pnt, 1 ); + + xi_even_fu_pnt( &itf_data->win_xi_pnt ); + XinWindowRectGet( itf_win, &itf_data->original_win_rct ); + if ( itf_data->font ) + itf_data->original_font_size = ( int ) XinFontSizeGet( itf_data->font ); + xi_add_window_to_list( itf_data->xin_win, itf ); + if ( xi_get_pref( XI_PREF_USE_APP_DATA ) ) + XinWindowAppDataSet( itf_data->xin_win, ( long ) ( itf ) ); + if ( itf_data->virtual_itf ) + { + xi_adjust_sb_vir_itf( itf_win, itf ); + XinScrollBarSet( itf_data->xin_win, XinScrollBarTypeHorizontal, + 0, 100, 1, 0 ); + XinScrollBarSet( itf_data->xin_win, XinScrollBarTypeVertical, + 0, 100, 1, 0 ); + } + xi_add_to_parent_list( itf, -1 ); + XinCoalesceInvalidates( itf_win, TRUE ); + create_children( xi_obj_def, itf, FALSE ); + /* queue up initialization event */ + xiev.type = XIE_INIT; + xiev.v.xi_obj = itf; + xi_enqueue( &xiev, itf ); + + XinCoalesceInvalidates( itf_win, FALSE ); +} + +/* ------------------------------------------------------------------------ */ +/* assign rectangles */ +/* ------------------------------------------------------------------------ */ +static void +assign_rectangles( XI_OBJ * itf, XinRect * dest_form_rect, + XinRect * dest_pixel_rect, + XinRect * source_form_rect, + XinRect * source_pixel_rect ) +{ + if ( source_pixel_rect->left || source_pixel_rect->right + || source_pixel_rect->top || source_pixel_rect->bottom ) + { + *dest_pixel_rect = *dest_form_rect = *source_pixel_rect; + xi_pu_to_fu( itf, ( XinPoint * ) dest_form_rect, 2 ); + } + else + { + *dest_pixel_rect = *dest_form_rect = *source_form_rect; + xi_fu_to_pu( itf, ( XinPoint * ) dest_pixel_rect, 2 ); + } +} + +/* ------------------------------------------------------------------------ */ +/* container_create */ +/* ------------------------------------------------------------------------ */ +static void +check_bitmap_max( XI_CONTAINER_DATA * cdata, XI_BITMAP * bitmap, int border ) +{ + short w, + h; + + if ( bitmap != NULL ) + { + xi_bitmap_size_get( bitmap, &w, &h ); + w += border; + h += border; + if ( w > cdata->pix_width ) + cdata->pix_width = w; + if ( h > cdata->pix_height ) + cdata->pix_height = h; + } +} + +static void +container_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * container ) +{ + XI_CONTAINER_DEF *cdef; + XI_OBJ_DEF *child; + XI_CONTAINER_DATA *cdata; + int i, + len, + max_len; + XI_BTN_TYPE button_type = XIBT_BUTTON; + int border; + + if ( xi_obj_def->nbr_children <= 0 ) + XinError( 20011, XinSeverityFatal, 0L ); + cdef = xi_obj_def->v.container; + cdata = ( XI_CONTAINER_DATA * ) + xi_tree_malloc( sizeof( XI_CONTAINER_DATA ), ( char * ) container ); + assign_rectangles( container->itf, &cdata->xi_rct, &cdata->rct, &cdef->xi_rct, + &cdef->pixel_rect ); + cdata->orientation = cdef->orientation; + cdata->tab_cid = cdef->tab_cid; + cdata->btn_height = cdef->btn_height; + cdata->btn_width = cdef->btn_width; + cdata->nbr_buttons = xi_obj_def->nbr_children; + cdata->packed = cdef->packed; + container->v.container = cdata; + + /* Determine largest bitmaps and longest text strings */ + if ( cdata->packed ) + border = 2 * ( ( int ) xi_get_pref( XI_PREF_CONTAINER_GRID_WIDTH ) + 2 ); + else + border = 10; + max_len = 0; + for ( i = 0; i < xi_obj_def->nbr_children; ++i ) + { + child = xi_obj_def->children[i]; + if ( child->type != XIT_BTN ) + XinError( 20012, XinSeverityFatal, 0L ); + if ( i == 0 ) + button_type = child->v.btn->type; + else if ( child->v.btn->type != button_type ) + XinError( 20013, XinSeverityFatal, 0L ); + if ( ( len = ( int ) strlen( child->v.btn->text ) ) > max_len ) + max_len = len; + check_bitmap_max( cdata, child->v.btn->up_bitmap, border ); + check_bitmap_max( cdata, child->v.btn->down_bitmap, border ); + check_bitmap_max( cdata, child->v.btn->disabled_bitmap, border ); + } + + xi_container_rect_calc( container, max_len, button_type ); + xi_add_to_parent_list( container, -1 ); + create_children( xi_obj_def, container, FALSE ); +} + +void +xi_container_set_rect_internal( XI_OBJ *xi_obj, XinRect *rect ) +{ + XI_CONTAINER_DATA *cdata; + int i, + len, + max_len; + int border; + XI_OBJ *child = NULL; + XinRect child_rect; + + cdata = xi_obj->v.container; + + /* Determine largest bitmaps and longest text strings */ + if ( cdata->packed ) + border = 2 * ( ( int ) xi_get_pref( XI_PREF_CONTAINER_GRID_WIDTH ) + 2 ); + else + border = 10; + max_len = 0; + for ( i = 0; i < xi_obj->nbr_children; ++i ) + { + child = xi_obj->children[i]; + if ( ( len = ( int ) strlen( child->v.btn->text ) ) > max_len ) + max_len = len; + check_bitmap_max( cdata, child->v.btn->up_bitmap, border ); + check_bitmap_max( cdata, child->v.btn->down_bitmap, border ); + check_bitmap_max( cdata, child->v.btn->disabled_bitmap, border ); + } + + cdata->rct = *rect; + + if (!cdata->packed && cdata->orientation == XI_STACK_VERTICAL) + { + switch ( child->v.btn->type ) + { + case XIBT_BUTTON: + case XIBT_BUTTON_CHECKBOX: + case XIBT_BUTTON_RADIOBTN: + case XIBT_TABBTN: + { + int top_ofst, + vert_spacing = 0, + vert_form_unit; + vert_form_unit = xi_get_fu_height( xi_obj->itf ); + if ( !cdata->packed ) + if ( ( vert_spacing = ( int ) xi_get_pref( XI_PREF_VERT_PIXEL_SPACING ) ) + == 0 ) + vert_spacing = ( int ) ( ( xi_get_pref( XI_PREF_VERT_SPACING ) + * vert_form_unit ) / XI_FU_MULTIPLE ); + top_ofst = vert_spacing / 2; + cdata->rct.top -= top_ofst; + cdata->rct.bottom -= top_ofst; + } + break; + default: + break; + } + } + + xi_container_rect_calc( xi_obj, max_len, child->v.btn->type ); + + switch (cdata->orientation) + { + case XI_STACK_VERTICAL: + for (i = 0; i < xi_obj->nbr_children; ++i ) + { + child = xi_obj->children[i]; + child_rect.top = cdata->rct.top + (cdata->step_down * i); + child_rect.bottom = child_rect.top + cdata->pix_height; + child_rect.left = cdata->rct.left; + child_rect.right = cdata->rct.right; + xi_set_rect_internal( child, &child_rect ); + } + break; + case XI_STACK_HORIZONTAL: + for (i = 0; i < xi_obj->nbr_children; ++i ) + { + child = xi_obj->children[i]; + child_rect.left = cdata->rct.left + (cdata->step_across * i); + child_rect.right = child_rect.left + cdata->pix_width; + child_rect.top = cdata->rct.top; + child_rect.bottom = cdata->rct.bottom; + xi_set_rect_internal( child, &child_rect ); + } + break; + case XI_GRID_VERTICAL: + { + int j; + for (i=0; i < cdata->nbr_across; i++) + { + for (j=0; j < cdata->nbr_down; j++) + { + int pos = i*cdata->nbr_down + j; + if (pos > xi_obj->nbr_children) + break; + child = xi_obj->children[pos]; + child_rect.top = cdata->rct.top + (cdata->step_down * j); + child_rect.left = cdata->rct.left + (cdata->step_across * i); + child_rect.bottom = child_rect.top + cdata->pix_height; + child_rect.right = child_rect.left + cdata->pix_width; + xi_set_rect_internal( child, &child_rect ); + } + } + } + break; + case XI_GRID_HORIZONTAL: + { + int j; + for (i=0; i < cdata->nbr_down; i++) + { + for (j=0; j < cdata->nbr_across; j++) + { + int pos = i*cdata->nbr_across + j; + if (pos > xi_obj->nbr_children) + break; + child = xi_obj->children[pos]; + child_rect.top = cdata->rct.top + (cdata->step_down * i); + child_rect.left = cdata->rct.left + (cdata->step_across * j); + child_rect.bottom = child_rect.top + cdata->pix_height; + child_rect.right = child_rect.left + cdata->pix_width; + xi_set_rect_internal( child, &child_rect ); + } + } + } + break; + } +} + +/* ------------------------------------------------------------------------ */ +/* rectangle_create */ +/* ------------------------------------------------------------------------ */ +static void +rectangle_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * rectangle ) +{ + XI_RECT_DATA *rect_data; + XI_RECT_DEF *rect_def = xi_obj_def->v.rect; + XinRect rct; + + rect_data = ( XI_RECT_DATA * ) xi_tree_malloc( sizeof( XI_RECT_DATA ), + rectangle ); + rect_data->fore_color = rect_def->fore_color; + rect_data->back_color = rect_def->back_color; + rect_data->hilight_color = rect_def->hilight_color; + rect_data->shadow_color = rect_def->shadow_color; + rect_data->well = rect_def->well; + rect_data->ridge = rect_def->ridge; + rect_data->attrib = rect_def->attrib; + rect_data->bitmap = xi_bitmap_copy( rect_def->bitmap ); +#if XIWS == XIWS_WM + rect_data->xi_rct = rect_def->xi_rct; + rct = rect_def->xi_rct; + rct.top = ( rct.top / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + rct.left = ( rct.left / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + rct.bottom = ( ( rct.bottom + XI_FU_MULTIPLE / 2 ) / XI_FU_MULTIPLE ) * + XI_FU_MULTIPLE; + rct.right = ( ( rct.right + XI_FU_MULTIPLE / 2 ) / XI_FU_MULTIPLE ) * + XI_FU_MULTIPLE; + rect_data->rct = rct; +#endif +#if XIWS != XIWS_WM + assign_rectangles( rectangle->itf, &rect_data->xi_rct, &rect_data->rct, + &rect_def->xi_rct, &rect_def->pixel_rect ); +#endif + rectangle->v.rect = rect_data; + xi_invalidate_rect( rectangle->itf->v.itf->xin_win, &rct ); + xi_add_to_parent_list( rectangle, -1 ); + if ( xi_obj_def->nbr_children != 0 ) + XinError( 20050, XinSeverityFatal, 0L ); +} + +/* ------------------------------------------------------------------------ */ +/* line_create */ +/* ------------------------------------------------------------------------ */ +static void +line_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * line ) +{ + XI_LINE_DATA *line_data; + XI_LINE_DEF *line_def = xi_obj_def->v.line; + XinPoint pnt1, + pnt2; + XinRect rct; + + line_data = ( XI_LINE_DATA * ) xi_tree_malloc( + sizeof( XI_LINE_DATA ), line ); + line_data->fore_color = line_def->fore_color; + line_data->back_color = line_def->back_color; + line_data->well = line_def->well; + line_data->attrib = line_def->attrib; + if ( line_def->pixel_pnt1.h || line_def->pixel_pnt1.v + || line_def->pixel_pnt2.h || line_def->pixel_pnt2.v ) + { + pnt1 = line_def->pixel_pnt1; + pnt2 = line_def->pixel_pnt2; + line_data->xi_pnt1 = pnt1; + line_data->xi_pnt2 = pnt2; + xi_pu_to_fu( line->itf, &line_data->xi_pnt1, 1 ); + xi_pu_to_fu( line->itf, &line_data->xi_pnt2, 1 ); + } + else + { + pnt1 = line_def->pnt1; + pnt2 = line_def->pnt2; + line_data->xi_pnt1 = pnt1; + line_data->xi_pnt2 = pnt2; +#if XIWS == XIWS_WM + pnt1.h = ( pnt1.h / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + pnt1.v = ( pnt1.v / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + pnt2.h = ( pnt2.h / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + pnt2.v = ( pnt2.v / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; +#endif +#if XIWS != XIWS_WM + xi_fu_to_pu( line->itf, &pnt1, 1 ); + xi_fu_to_pu( line->itf, &pnt2, 1 ); +#endif + } + line_data->pnt1 = pnt1; + line_data->pnt2 = pnt2; + line->v.line = line_data; + rct.top = min( pnt1.v, pnt2.v ); + rct.left = min( pnt1.h, pnt2.h ); + rct.bottom = max( pnt1.v, pnt2.v ); + rct.right = max( pnt1.h, pnt2.h ); + xi_invalidate_rect( line->itf->v.itf->xin_win, &rct ); + xi_add_to_parent_list( line, -1 ); + if ( xi_obj_def->nbr_children != 0 ) + XinError( 20051, XinSeverityFatal, 0L ); +} + +/* ------------------------------------------------------------------------ */ +/* button_create */ +/* ------------------------------------------------------------------------ */ +static void +button_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * button ) +{ + XI_BTN_DATA *btn_data; + XI_BTN_DEF *btn_def = xi_obj_def->v.btn; + XinRect rct; + XinWindow itf_win; + + itf_win = button->itf->v.itf->xin_win; + btn_data = ( XI_BTN_DATA * ) xi_tree_malloc( sizeof( XI_BTN_DATA ), button ); + btn_data->attrib = btn_def->attrib; + btn_data->tab_cid = btn_def->tab_cid; + btn_data->dflt = btn_def->dflt; + btn_data->cancel = btn_def->cancel; + btn_data->down_icon_rid = btn_def->down_icon_rid; + btn_data->up_icon_rid = btn_def->up_icon_rid; + btn_data->disabled_icon_rid = btn_def->disabled_icon_rid; + btn_data->icon_x = btn_def->icon_x; + btn_data->icon_y = btn_def->icon_y; + btn_data->up_bitmap = xi_bitmap_copy( btn_def->up_bitmap ); + btn_data->down_bitmap = xi_bitmap_copy( btn_def->down_bitmap ); + btn_data->disabled_bitmap = xi_bitmap_copy( btn_def->disabled_bitmap ); + btn_data->text = ( char * ) + xi_tree_malloc( strlen( btn_def->text ) + 1, btn_data ); + btn_data->checked = btn_def->checked; + btn_data->type = btn_def->type; + btn_data->fore_color = btn_def->fore_color; + btn_data->draw_as = btn_def->draw_as; + btn_data->drawable = btn_def->drawable; + btn_data->mnemonic = btn_def->mnemonic; + btn_data->mnemonic_instance = btn_def->mnemonic_instance; + XinWindowHotkeySet( itf_win, btn_data->mnemonic ); + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + if ( btn_def->font ) + XinFontCopy( &btn_data->font, btn_def->font ); + } +#ifdef XI_USE_XVT + else + { + if ( btn_def->font_id ) + btn_data->font = XinFontXvtConvert( btn_def->font_id ); + } +#endif + + strcpy( btn_data->text, btn_def->text ); + assign_rectangles( button->itf, &btn_data->xi_rct, &btn_data->rct, + &btn_def->xi_rct, &btn_def->pixel_rect ); + button->v.btn = btn_data; + xi_button_rect_calc( button, button->parent->nbr_children ); + rct = btn_data->rct; +#ifdef XI_USE_XVT + if ( !xi_get_native_controls( button ) ) + xi_invalidate_rect( itf_win, &rct ); + else + { + XinWindowDef Def; + + MEMCLEAR( Def ); + Def.control_id = xi_obj_def->cid; + switch ( btn_def->type ) + { + case XIBT_BUTTON: + case XIBT_BUTTON_CHECKBOX: + case XIBT_BUTTON_RADIOBTN: + Def.type = XinWindowTypeButton; + break; + case XIBT_RADIOBTN: + case XIBT_TABBTN: + Def.type = XinWindowTypeRadioButton; + break; + case XIBT_CHECKBOX: + Def.type = XinWindowTypeCheckBox; + break; + } + Def.border_style = XinBorderFixed; + Def.p_rect = &rct; + Def.visible = ( BOOLEAN ) ( ( btn_def->attrib & XI_ATR_VISIBLE ) != 0 ); + Def.enabled = ( BOOLEAN ) ( ( btn_def->attrib & XI_ATR_ENABLED ) != 0 ); + Def.parent = itf_win; + Def.title = btn_data->text; + Def.back_color = button->itf->v.itf->back_color; + if ( btn_data->font ) + XinFontCopy( &Def.font, btn_data->font ); + else if ( button->itf->v.itf->font ) + XinFontCopy( &Def.font, button->itf->v.itf->font ); + else + Def.font = xi_get_system_font(); + btn_data->btnctl = XinWindowCreate( &Def ); + if ( btn_def->checked && Def.type == XinWindowTypeCheckBox ) + XinWindowCheckBox( btn_data->btnctl, TRUE ); + } +#else + xi_invalidate_rect( itf_win, &rct ); +#endif + xi_add_to_parent_list( button, -1 ); + if ( xi_obj_def->nbr_children != 0 ) + XinError( 20052, XinSeverityFatal, 0L ); +} + +/* ------------------------------------------------------------------------ */ +/* form_create */ +/* ------------------------------------------------------------------------ */ +static void +form_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * form ) +{ + XI_FORM_DATA *form_data; + XI_FORM_DEF *form_def; + + form_def = xi_obj_def->v.form; + form_data = ( XI_FORM_DATA * ) + xi_tree_malloc( sizeof( XI_FORM_DATA ), ( char * ) form ); + form_data->attrib = XI_ATR_VISIBLE | XI_ATR_ENABLED; + form_data->tab_cid = form_def->tab_cid; + form->v.form = form_data; + xi_add_to_parent_list( form, -1 ); + create_children( xi_obj_def, form, FALSE ); +} + +/* ------------------------------------------------------------------------ */ +/* field_create */ +/* ------------------------------------------------------------------------ */ +static void +field_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * field ) +{ + STX_DEF stxdef; + XI_FIELD_DATA *field_data; + XI_FIELD_DEF *xi_fd; + int btn_dim_x; + int btn_dim_x2; + int fu_width; + int fu_height; + int edit_height; + int btn_space; + XinWindow itf_win; + int leading, + ascent, + descent, + font_height; + + itf_win = field->itf->v.itf->xin_win; + fu_width = xi_get_fu_width( field->itf ); + fu_height = xi_get_fu_height( field->itf ); + xi_fd = xi_obj_def->v.field; + if ( xi_fd->button_width > 0 ) + { + btn_dim_x = xi_fd->button_width; + if (btn_dim_x < 6) + btn_dim_x = 6; + } else { + btn_dim_x = ( fu_height * XI_FU_MULTIPLE ) / fu_width; + /* btn_dim_x is actual width of button */ +#if XIWS != XIWS_WM + /* make buttons 70% wide as high */ + btn_dim_x = ( int ) ( ( long ) btn_dim_x * 83L / 100L ); +#endif + } + btn_space = btn_dim_x / 6; + /* btn_dim_x2 is the button width + space, rounded up to */ + /* the next even form unit */ + btn_dim_x2 = btn_dim_x + btn_space; + btn_dim_x2 = ( ( btn_dim_x2 + XI_FU_MULTIPLE ) / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + if (xi_fd->button_width == 0) + btn_dim_x = ( int ) ( ( ( long ) btn_dim_x * fu_width ) / XI_FU_MULTIPLE ); + btn_dim_x2 = ( int ) ( ( ( long ) btn_dim_x2 * fu_width ) / XI_FU_MULTIPLE ); + MEMCLEAR( stxdef ); + stxdef.cid = xi_obj_def->cid; + stxdef.pnt = xi_fd->pixel_origin; + if ( stxdef.pnt.v == 0 && stxdef.pnt.h == 0 ) + { + stxdef.pnt = xi_fd->pnt; + xi_fu_to_pu( field->itf, &stxdef.pnt, 1 ); + } + stxdef.pixel_width = xi_fd->pixel_width; + if ( stxdef.pixel_width == 0 ) + stxdef.pixel_width = xi_fd->field_width * fu_width / XI_FU_MULTIPLE; + stxdef.xi_rct = xi_fd->xi_rct; + field_data = ( XI_FIELD_DATA * ) xi_tree_malloc( sizeof( XI_FIELD_DATA ), + ( char * ) field ); + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + if ( xi_fd->font ) + { + XinFontCopy( &stxdef.font, xi_fd->font ); + field_data->font_set = TRUE; + } + } +#ifdef XI_USE_XVT + else + { + if ( xi_fd->font_id ) + { + stxdef.font = XinFontXvtConvert( xi_fd->font_id ); + field_data->font_set = TRUE; + } + } +#endif + if ( !stxdef.font ) + { + if ( field->itf->v.itf->font ) + { + stxdef.font = field->itf->v.itf->font; + field_data->font_set = FALSE; + } + else + { + stxdef.font = xi_get_system_font( ); + field_data->font_set = FALSE; + } + } + field_data->rct.top = stxdef.pnt.v; + field_data->rct.left = stxdef.pnt.h; + field_data->rct.right = stxdef.pnt.h + stxdef.pixel_width; + field_data->rct.bottom = stxdef.pnt.v + fu_height; + XinWindowFontMap( itf_win, stxdef.font ); + XinFontMetricsGet( stxdef.font, &leading, &ascent, &descent ); + font_height = ascent + leading + descent; + edit_height = font_height + ( 2 * EDIT_BORDER_WIDTH_Y ) + + ( 2 * EDIT_BORDER_SPACE_Y ); + if ( !( xi_fd->xi_rct.top || xi_fd->xi_rct.bottom || + xi_fd->xi_rct.left || xi_fd->xi_rct.right ) ) + { + if ( xi_fd->button ) + { + + field_data->btn_rct.top = stxdef.pnt.v; + if ( xi_fd->button_on_left ) + { + field_data->btn_rct.left = stxdef.pnt.h; + field_data->btn_rct.right = + field_data->btn_rct.left + btn_dim_x; + if (field_data->no_button_space == XinFlagFalse || + (field_data->no_button_space == XinFlagNotSet && + !xi_get_pref( XI_PREF_NO_BUTTON_SPACE ))) + { + if ( xi_fd->pixel_button_distance ) + stxdef.pnt.h = field_data->btn_rct.right + + xi_fd->pixel_button_distance; + else + stxdef.pnt.h += btn_dim_x2; + } + } + else + { +#if XIWS == XIWS_WM + BOOLEAN b; + + b = ( BOOLEAN ) ( xi_fd->attrib & XI_ATR_BORDER ); + field_data->btn_rct.left = stxdef.pnt.h + stxdef.pixel_width + + ( b ? 24 : 8 ); + field_data->btn_rct.right = field_data->btn_rct.left + 8; +#endif +#if XIWS != XIWS_WM + /* TODO problem with this code */ + /* TODO Need a boolean - place button next to field */ + /* TODO Need to handle correctly if use a button on a field with xi_rct + * specified */ + if ( xi_fd->pixel_button_distance ) + { + field_data->btn_rct.left = stxdef.pnt.h + stxdef.pixel_width + + xi_fd->pixel_button_distance; + field_data->btn_rct.right = field_data->btn_rct.left + btn_dim_x; + } + else + { + int right; + + right = stxdef.pnt.h + stxdef.pixel_width + btn_dim_x2; + /* convert to form units */ + right = ( int ) ( ( ( long ) right * XI_FU_MULTIPLE ) / fu_width ); + /* round up to nearest FU multiple */ + right = ( ( right + XI_FU_MULTIPLE ) / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + /* convert to pixels */ + right = ( int ) ( ( ( long ) right * fu_width ) / XI_FU_MULTIPLE ); + field_data->btn_rct.right = right; + field_data->btn_rct.left = right - btn_dim_x; + } +#endif + } + } + } + else + { + field_data->rct = xi_fd->xi_rct; + xi_fu_to_pu( field->itf, ( XinPoint * ) & field_data->rct, 2 ); + if ( xi_fd->button ) + { + field_data->btn_rct = xi_fd->xi_rct; + xi_fu_to_pu( field->itf, ( XinPoint * ) & field_data->btn_rct, 2 ); + if ( xi_fd->button_on_left ) + { + XinPoint p; + + p.h = btn_dim_x2; + xi_pu_to_fu( field->itf, &p, 1 ); + field_data->btn_rct.right = + field_data->btn_rct.left + btn_dim_x; + if (field_data->no_button_space == XinFlagFalse || + (field_data->no_button_space == XinFlagNotSet && + !xi_get_pref( XI_PREF_NO_BUTTON_SPACE ))) + { + stxdef.xi_rct.left += p.h; + stxdef.xi_rct.right += p.h; + } + } + else + { + int right; + + right = field_data->btn_rct.right + btn_space + btn_dim_x2; + /* convert to form units */ + right = ( int ) ( ( ( long ) right * XI_FU_MULTIPLE ) / fu_width ); + /* round up to nearest FU multiple */ + right = ( ( right + XI_FU_MULTIPLE ) / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + /* convert to pixels */ + right = ( int ) ( ( ( long ) right * fu_width ) / XI_FU_MULTIPLE ); + field_data->btn_rct.right = right; + field_data->btn_rct.left = right - btn_dim_x; + } + } + } + field_data->btn_rct.bottom = field_data->btn_rct.top + + edit_height; + stxdef.pix_char_width = fu_width; + stxdef.attrib = xi_fd->attrib; + stxdef.text_size = xi_fd->text_size; + stxdef.back_color = xi_fd->back_color; + stxdef.enabled_color = xi_fd->enabled_color; + stxdef.disabled_color = xi_fd->disabled_color; + stxdef.disabled_back_color = xi_fd->disabled_back_color; + stxdef.active_color = xi_fd->active_color; + stxdef.active_back_color = xi_fd->active_back_color; + stxdef.hilight_color = xi_fd->hilight_color; + stxdef.shadow_color = xi_fd->shadow_color; + stxdef.stx_cb = xi_stx_cb; + stxdef.app_data = ( long ) ( field ); + stxdef.parent = ( char * ) field_data; + stxdef.well = xi_fd->well; + stxdef.platform = xi_fd->platform; + stxdef.auto_tab = xi_fd->auto_tab; + stxdef.scroll_bar = xi_fd->scroll_bar; + stxdef.cr_ok = xi_fd->cr_ok; + stxdef.var_len_text = xi_fd->var_len_text; + stxdef.parent_obj = field; + stxdef.button = xi_fd->button; + stxdef.button_on_left = xi_fd->button_on_left; + stxdef.button_rect = field_data->btn_rct; + stxdef.no_button_space = xi_fd->no_button_space; + stxdef.button_width = xi_fd->button_width; + /* The stx_create() can change the field button rect if the button goes inside + the field area. */ + field_data->stx = stx_create( itf_win, &stxdef, &field_data->btn_rct ); + field_data->tab_cid = xi_fd->tab_cid; + field_data->button = xi_fd->button; + field_data->button_on_left = xi_fd->button_on_left; + field_data->no_button_space = xi_fd->no_button_space; + field_data->icon_rid = xi_fd->icon_rid; + field_data->button_bitmap = xi_bitmap_copy( xi_fd->button_bitmap ); + field_data->button_width = xi_fd->button_width; + field_data->well = xi_fd->well; + field_data->platform = xi_fd->platform; + field_data->xi_rct = xi_fd->xi_rct; + field_data->xi_pnt = xi_fd->pnt; + field_data->field_width = xi_fd->field_width; + field_data->var_len_text = xi_fd->var_len_text; + field_data->mnemonic = xi_fd->mnemonic; + XinWindowHotkeySet( itf_win, field_data->mnemonic ); + field->v.field = field_data; + xi_add_to_parent_list( field, -1 ); + if ( xi_obj_def->nbr_children != 0 ) + XinError( 20053, XinSeverityFatal, 0L ); +} + +void +xi_field_set_rect_internal( XI_OBJ *field_obj, XinRect *rect ) +{ + XI_FIELD_DATA *field_data; + int btn_dim_x; + int btn_dim_x2; + int fu_width; + int fu_height; + int edit_height; + int btn_space; + XinWindow itf_win; + XinRect stx_rect; + int leading, + ascent, + descent, + font_height; + + field_data = field_obj->v.field; + itf_win = field_obj->itf->v.itf->xin_win; + fu_width = xi_get_fu_width( field_obj->itf ); + fu_height = xi_get_fu_height( field_obj->itf ); + if ( field_data->button_width > 0 ) + { + btn_dim_x = field_data->button_width; + if (btn_dim_x < 6) + btn_dim_x = 6; + } else { + btn_dim_x = ( fu_height * XI_FU_MULTIPLE ) / fu_width; + /* btn_dim_x is actual width of button */ +#if XIWS != XIWS_WM + /* make buttons 70% wide as high */ + btn_dim_x = ( int ) ( ( long ) btn_dim_x * 83L / 100L ); +#endif + } + btn_space = btn_dim_x / 6; + /* btn_dim_x2 is the button width + space, rounded up to */ + /* the next even form unit */ + btn_dim_x2 = btn_dim_x + btn_space; + btn_dim_x2 = ( ( btn_dim_x2 + XI_FU_MULTIPLE ) / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + if (field_data->button_width == 0) + btn_dim_x = ( int ) ( ( ( long ) btn_dim_x * fu_width ) / XI_FU_MULTIPLE ); + btn_dim_x2 = ( int ) ( ( ( long ) btn_dim_x2 * fu_width ) / XI_FU_MULTIPLE ); + XinWindowFontMap( itf_win, xi_text_font_get( stx_xi_text_get( field_data->stx ) ) ); + XinFontMetricsGet( xi_text_font_get( stx_xi_text_get( field_data->stx ) ), + &leading, &ascent, &descent ); + font_height = ascent + leading + descent; + edit_height = font_height + ( 2 * EDIT_BORDER_WIDTH_Y ) + + ( 2 * EDIT_BORDER_SPACE_Y ); + field_data->rct = *rect; + stx_rect = *rect; + if ( field_data->button ) + { + field_data->btn_rct = *rect; + if ( field_data->button_on_left ) + { + XinPoint p; + + p.h = btn_dim_x2; + xi_pu_to_fu( field_obj->itf, &p, 1 ); + field_data->btn_rct.right = + field_data->btn_rct.left + btn_dim_x; + if (field_data->no_button_space == XinFlagFalse || + (field_data->no_button_space == XinFlagNotSet && + !xi_get_pref( XI_PREF_NO_BUTTON_SPACE ))) + { + stx_rect.left += p.h; + stx_rect.right += p.h; + } + } + else + { + int right; + + right = field_data->btn_rct.right + btn_space + btn_dim_x2; + /* convert to form units */ + right = ( int ) ( ( ( long ) right * XI_FU_MULTIPLE ) / fu_width ); + /* round up to nearest FU multiple */ + right = ( ( right + XI_FU_MULTIPLE ) / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + /* convert to pixels */ + right = ( int ) ( ( ( long ) right * fu_width ) / XI_FU_MULTIPLE ); + field_data->btn_rct.right = right; + field_data->btn_rct.left = right - btn_dim_x; + } + } + field_data->btn_rct.bottom = field_data->btn_rct.top + + edit_height; + /* The stx_set_rect() can change the field button rect if the button goes inside + the field area. */ + stx_set_rect( itf_win, field_data->stx, &stx_rect, &field_data->btn_rct ); + { + XinRect empty_rect = {0,0,0,0}; + XinPoint empty_point = { 0,0 } ; + field_data->xi_rct = empty_rect; + field_data->xi_pnt = empty_point; + } +} + + +/* ------------------------------------------------------------------------ */ +/* text_create */ +/* ------------------------------------------------------------------------ */ +static void +text_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * text ) +{ + XI_TEXT_DATA *text_data; + XI_TEXT_DEF *text_def = xi_obj_def->v.text; + + text_data = ( XI_TEXT_DATA * ) + xi_tree_malloc( sizeof( XI_TEXT_DATA ), text ); + text_data->attrib = text_def->attrib; + assign_rectangles( text->itf, &text_data->xi_rct, &text_data->rct, + &text_def->xi_rct, &text_def->pixel_rect ); + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + if ( text_def->font ) + XinFontCopy( &text_data->font, text_def->font ); + } +#ifdef XI_USE_XVT + else + { + if ( text_def->font_id ) + text_data->font = XinFontXvtConvert( text_def->font_id ); + } +#endif + text_data->text = + ( char * ) xi_tree_malloc( strlen( text_def->text ) + 1, text ); + strcpy( text_data->text, text_def->text ); + text_data->fore_color = text_def->fore_color; + text_data->back_color = text_def->back_color; + text_data->mnemonic = text_def->mnemonic; + text_data->mnemonic_instance = text_def->mnemonic_instance; + text->v.text = text_data; + xi_invalidate_rect( text->itf->v.itf->xin_win, &text_data->rct ); + xi_add_to_parent_list( text, -1 ); + if ( xi_obj_def->nbr_children != 0 ) + XinError( 20055, XinSeverityFatal, 0L ); +} + +/* ------------------------------------------------------------------------ */ +/* group_create */ +/* ------------------------------------------------------------------------ */ +static void +group_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * group, + BOOLEAN creating_list ) +{ + XI_GROUP_DEF *group_def = xi_obj_def->v.group; + XI_GROUP_DATA *group_data; + + group_data = ( XI_GROUP_DATA * ) xi_tree_malloc( sizeof( XI_GROUP_DATA ), + group ); + group_data->nbr_cids = group_def->nbr_cids; + group_data->cidlist = ( int * ) xi_tree_malloc( + sizeof( int ) * group_def->nbr_cids, group_data ); + memcpy( ( char * ) group_data->cidlist, + ( char * ) group_def->cids, + sizeof( int ) * group_def->nbr_cids ); + group->v.group = group_data; + xi_add_to_parent_list( group, -1 ); + create_children( xi_obj_def, group, creating_list ); +} + +/* ------------------------------------------------------------------------ */ +/* column_create */ +/* ------------------------------------------------------------------------ */ +static void +column_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * obj, + BOOLEAN creating_list ) +{ + LM_COLUMN_DEF lm_column_def; + XI_COLUMN_DATA *column_data; + XI_COLUMN_DEF *col_def; + XI_OBJ **column; + int i; + int pixel_width; + LM_DATA *lmp; + XI_LIST_DATA *list_data; + int char_pixel_width; + + list_data = obj->parent->v.list; + lmp = ( LM_DATA * ) list_data->lm; + MEMCLEAR( lm_column_def ); + column_data = ( XI_COLUMN_DATA * ) xi_tree_malloc( sizeof( XI_COLUMN_DATA ), + ( char * ) obj ); + col_def = xi_obj_def->v.column; + lm_column_def.attrib = col_def->attrib; + char_pixel_width = xi_get_fu_width( obj->itf ); + if ( col_def->pixel_width == 0 ) + { + if ( xi_get_xil_pref( obj->parent->parent ) ) + col_def->pixel_width = col_def->width * char_pixel_width; + else + col_def->pixel_width = col_def->width * char_pixel_width / XI_FU_MULTIPLE; + } + pixel_width = col_def->pixel_width; + if ( list_data->width ) + { + pixel_width = lmp->pixel_width; + for ( i = 0; i < min( lmp->fixed_columns, lmp->nbr_columns ); ++i ) + pixel_width -= lmp->lm_column_data[i]->pix_width; + pixel_width = min( pixel_width, col_def->pixel_width ); + } + + if ( col_def->position ) + lm_column_def.position = min( col_def->position, lmp->nbr_columns ); + else + { + for ( lm_column_def.position = i = 0, + column = obj->parent->children; + i < obj->parent->nbr_children; i++, column++ ) + { + if ( ( *column )->type != XIT_COLUMN ) + XinError( 20015, XinSeverityFatal, 0L ); + if ( ( *column )->v.column->sort_number < + col_def->sort_number ) + lm_column_def.position++; + } + } + lm_column_def.pix_width = pixel_width; + lm_column_def.text_size = col_def->text_size; + if ( lm_column_def.text_size < 2 ) + lm_column_def.text_size = 2; + lm_column_def.heading_text = col_def->heading_text; + lm_column_def.center_heading = col_def->center_heading; +#if XIWS != XIWS_WM + lm_column_def.heading_well = col_def->heading_well; + lm_column_def.heading_platform = col_def->heading_platform; + lm_column_def.column_well = col_def->column_well; + lm_column_def.column_platform = col_def->column_platform; +#else + lm_column_def.heading_well = FALSE; + lm_column_def.heading_platform = FALSE; + lm_column_def.column_well = FALSE; + lm_column_def.column_platform = FALSE; +#endif + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + if ( col_def->font ) + XinFontCopy( &lm_column_def.font, col_def->font ); + } +#ifdef XI_USE_XVT + else + { + if ( col_def->font_id ) + lm_column_def.font = XinFontXvtConvert( col_def->font_id ); + } +#endif + lm_column_def.icon_rid = col_def->icon_rid; + lm_column_def.icon_x = col_def->icon_x; + lm_column_def.icon_y = col_def->icon_y; + lm_column_def.bitmap = xi_bitmap_copy( col_def->bitmap ); + lm_column_def.size_rows = col_def->size_rows; + lm_column_def.suppress_update_heading = col_def->suppress_update_heading; + lm_column_def.suppress_update_cells = col_def->suppress_update_cells; + lm_column_def.vertical_align_center = col_def->vertical_align_center; + lm_column_def.vertical_align_bottom = col_def->vertical_align_bottom; + lm_column_def.wrap_text = col_def->wrap_text; + if ( col_def->wrap_text ) + if ( lmp->max_lines_in_cell == 1 ) + lmp->max_lines_in_cell = 5; + lm_column_def.wrap_text_scrollbar = col_def->wrap_text_scrollbar; + lm_column_def.cr_ok = col_def->cr_ok; + lm_column_def.var_len_text = col_def->var_len_text; + lm_column_def.auto_tab = col_def->auto_tab; + lm_column_def.icon_mode = col_def->icon_mode; + + obj->v.column = column_data; + column_data->sort_number = col_def->sort_number; + xi_add_to_parent_list( obj, lm_column_def.position ); + lm_create_column( obj->parent->v.list->lm, &lm_column_def, ( BOOLEAN ) ( !creating_list ), + TRUE ); + if ( xi_obj_def->nbr_children != 0 ) + XinError( 20056, XinSeverityFatal, 0L ); + if ( list_data->width == 0 && list_data->sb_win ) + xi_move_list_scroll_bar( obj->parent ); +} + +/* ------------------------------------------------------------------------ */ +/* list_data_create */ +/* ------------------------------------------------------------------------ */ +static void +list_data_create( XI_LIST_DEF * list_def, XI_OBJ * list ) +{ + XI_LIST_DATA *list_data; + + list_data = ( XI_LIST_DATA * ) xi_tree_malloc( sizeof( XI_LIST_DATA ), + ( char * ) list ); + list->v.list = list_data; + list_data->xi_pnt = list_def->xi_pnt; + list_data->height = list_def->height; + list_data->one_row_list = list_def->one_row_list; + list_data->start_percent = list_def->start_percent; + list_data->horz_sync_list = list_def->horz_sync_list; + list_data->vert_sync_list = list_def->vert_sync_list; + list_data->row_focus_border = list_def->row_focus_border; + list_data->row_focus_border_color = list_def->row_focus_border_color; + list_data->max_lines_in_cell = list_def->max_lines_in_cell; + list_data->single_select = list_def->single_select; + list_data->scroll_on_thumb_track = list_def->scroll_on_thumb_track; + + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + if ( list_def->font ) + XinFontCopy( &list_data->font, list_def->font ); + } +#ifdef XI_USE_XVT + else + { + if ( list_def->font_id ) + list_data->font = XinFontXvtConvert( list_def->font_id ); + } +#endif + if ( !list_data->font ) + { + if ( list->itf->v.itf->font ) + XinFontCopy( &list_data->font, list->itf->v.itf->font ); + else + XinFontCopy( &list_data->font, xi_get_system_font( ) ); + } +} + +/* ------------------------------------------------------------------------ */ +/* list_module_def_create */ +/* ------------------------------------------------------------------------ */ +static void +list_module_def_create( LM_DEF * lm_def, XI_LIST_DEF * list_def, + XI_OBJ * list ) +{ + /* create LM */ + XI_LIST_DATA *list_data = list->v.list; + + MEMCLEAR( *lm_def ); + lm_def->cid = list->cid; + lm_def->pnt = list_def->xi_pnt; + if ( xi_get_xil_pref( list->parent ) ) + lm_def->pixel_height = list_def->height; + else + { + if ( list_def->pixel_origin.h || list_def->pixel_origin.v ) + lm_def->pnt = list_def->pixel_origin; + else + { + lm_def->pnt = list_def->xi_pnt; + xi_fu_to_pu( list->itf, &lm_def->pnt, 1 ); + } + if ( list_def->pixel_height ) + lm_def->pixel_height = list_def->pixel_height; + else + lm_def->pixel_height = list_def->height * xi_get_fu_height( list->itf ) + / XI_FU_MULTIPLE; + } + lm_def->pix_char_width = xi_get_fu_width( list->itf ); + lm_def->attrib = list_def->attrib; + lm_def->back_color = list_def->back_color; + lm_def->enabled_color = list_def->enabled_color; + lm_def->disabled_color = list_def->disabled_color; + lm_def->disabled_back_color = list_def->disabled_back_color; + lm_def->active_color = list_def->active_color; + lm_def->active_back_color = list_def->active_back_color; + lm_def->white_space_color = list_def->white_space_color; + if ( !lm_def->white_space_color ) + lm_def->white_space_color = XI_COLOR_LTGRAY; + lm_def->rule_color = list_def->rule_color; + if ( !lm_def->rule_color ) + lm_def->rule_color = XI_COLOR_BLACK; + lm_def->lm_cb = xi_lm_cb; + if ( list_data->font ) + lm_def->font = list_data->font; + else if ( list->itf->v.itf->font ) + lm_def->font = list->itf->v.itf->font; + else + lm_def->font = xi_get_system_font( ); + if ( list_def->font ) + lm_def->is_list_font = TRUE; + if ( list_def->font_id ) + lm_def->is_list_font = TRUE; + lm_def->no_heading = list_def->no_heading; + lm_def->one_row_list = list_def->one_row_list; + lm_def->sizable_columns = list_def->sizable_columns; + lm_def->movable_columns = list_def->movable_columns; + lm_def->fixed_columns = list_def->fixed_columns; +#if XIWS == XIWS_WM + lm_def->min_cell_height = 8; + lm_def->min_heading_height = list_def->min_heading_height; +#else + lm_def->min_cell_height = list_def->min_cell_height; + lm_def->min_heading_height = list_def->min_heading_height; +#endif + lm_def->no_horz_lines = list_def->no_horz_lines; + lm_def->no_vert_lines = list_def->no_vert_lines; + lm_def->first_vis_column = list_def->first_vis_column; + lm_def->drop_and_delete = list_def->drop_and_delete; + lm_def->select_cells = list_def->select_cells; + lm_def->get_all_records = list_def->get_all_records; + lm_def->resize_with_window = list_def->resize_with_window; + lm_def->horz_sync_list = list_def->horz_sync_list; + lm_def->vert_sync_list = list_def->vert_sync_list; + lm_def->row_focus_border = list_def->row_focus_border; + lm_def->row_focus_border_color = list_def->row_focus_border_color; + lm_def->single_select = list_def->single_select; + lm_def->retain_back_color_on_select = list_def->retain_back_color_on_select; + lm_def->drag_and_drop_rows = list_def->drag_and_drop_rows; + lm_def->drag_rows_autoscroll = list_def->drag_rows_autoscroll; + lm_def->button_on_cell_focus = list_def->button_on_cell_focus; + lm_def->position_by_typing_cid = list_def->position_by_typing_cid; + if ( xi_get_xil_pref( list->parent ) ) + lm_def->pixel_width = list_def->width; + else + { + if ( list_def->pixel_width ) + lm_def->pixel_width = list_def->pixel_width; + else + { + XinPoint p; + + p.h = list_def->width; + p.v = 0; + xi_fu_to_pu( list->itf, &p, 1 ); + lm_def->pixel_width = p.h; + } + lm_def->max_lines_in_cell = list_def->max_lines_in_cell; + } +} + +/* ------------------------------------------------------------------------ */ +/* lm_get_width */ +/* ------------------------------------------------------------------------ */ +static int +lm_get_width( XI_OBJ_DEF * obj_def, int fu_width, int columns, short *fixed_cols ) +{ + XI_LIST_DEF *list_def = obj_def->v.list; + int i; + int number_fixed_columns; + int fixed_column_width; + int max_movable_column; + int movable_column_width; + int total_columns; + int width; + XI_OBJ_DEF **column; + int list_pix_width; + + /* calculate specified width of list */ + if ( xi_def_get_xil_pref( obj_def->parent ) ) + list_pix_width = obj_def->v.list->width; + else + { + if ( obj_def->v.list->pixel_width ) + list_pix_width = obj_def->v.list->pixel_width; + else + list_pix_width = obj_def->v.list->width * fu_width / XI_FU_MULTIPLE; + } + + /* calculate all pixel widths */ + column = obj_def->children; + total_columns = obj_def->nbr_children; + + /* If it is an empty list, just return */ + if ( total_columns <= 0 ) + return 0; + + for ( i = 0; i < total_columns; ++column, ++i ) + { + XI_COLUMN_DEF *col = ( *column )->v.column; + + if ( !col->pixel_width ) + { + if ( xi_def_get_xil_pref( obj_def->parent ) ) + col->pixel_width = col->width * fu_width; + else + col->pixel_width = col->width * fu_width / XI_FU_MULTIPLE; + } + } + /* find sum of fixed column widths */ + number_fixed_columns = min( list_def->fixed_columns, total_columns - 1 ); + column = obj_def->children; + fixed_column_width = 0; + for ( i = 0; i < number_fixed_columns; ++column, ++i ) + { + fixed_column_width += ( *column )->v.column->pixel_width + lm_get_col_spacing( ); + if ( fixed_column_width >= list_pix_width ) + { + number_fixed_columns = i; + fixed_column_width -= ( *column )->v.column->pixel_width + lm_get_col_spacing( ); + break; + } + } + /* remove extra internal rule width */ + fixed_column_width -= lm_get_col_spacing( ); + /* find largest moveable column width, and sum of movable column widths */ + max_movable_column = 0; + movable_column_width = 0; + if ( columns <= number_fixed_columns ) + { + columns = number_fixed_columns; + /* if we have any movable columns, columns must be at least */ + /* # fixed_columns + 1 */ + if ( total_columns > number_fixed_columns ) + columns++; + } + for ( ; i < columns; ++column, ++i ) + { + XI_COLUMN_DEF *col = ( *column )->v.column; + + movable_column_width += col->pixel_width; + max_movable_column = max( max_movable_column, col->pixel_width ); + } + for ( ; i < total_columns; ++column, ++i ) + max_movable_column = max( max_movable_column, + ( *column )->v.column->pixel_width ); + /* add the internal column rules for movable columns */ + if ( columns > number_fixed_columns + 1 ) + movable_column_width += ( columns - number_fixed_columns - 1 ) + * lm_get_col_spacing( ); + /* use either the sum of the movable columns, or the largest movable column */ + movable_column_width = max( movable_column_width, max_movable_column ); + /* calculate width */ + width = 2 * BORDER_WIDTH + fixed_column_width + movable_column_width; + /* add the rule between fixed & movable columns */ + if ( columns > number_fixed_columns && number_fixed_columns > 0 ) + width += lm_get_col_spacing( ); + *fixed_cols = number_fixed_columns; + return width; +} + +/* ------------------------------------------------------------------------ */ +/* xi_list_def_get_client_width */ +/* ------------------------------------------------------------------------ */ +int +xi_list_def_get_client_width( XI_OBJ_DEF * obj_def, int columns ) +{ + XinFont *font; + int width; + short temp; + + font = xi_def_get_font( obj_def ); + width = xi_get_fu_width_font( font ); + XinFontDestroy( font ); + return lm_get_width( obj_def, width, columns, &temp ); +} + +/* ------------------------------------------------------------------------ */ +/* xi_list_def_get_outer_width */ +/* ------------------------------------------------------------------------ */ +int +xi_list_def_get_outer_width( XI_OBJ_DEF * obj_def, int columns ) +{ + int result; + + result = xi_list_def_get_client_width( obj_def, columns ); + if ( obj_def->v.list->scroll_bar ) + result += ( int ) xi_get_pref( XI_PREF_SB_OFFSET ) + + ( int ) xi_get_pref( XI_PREF_SB_WIDTH ); +#if XIWS == XIWS_WM + return result; +#else + return result + 2 * BORDER_WIDTH; +#endif +} + +/* ------------------------------------------------------------------------ */ +/* list_create */ +/* ------------------------------------------------------------------------ */ +static void +list_create( XI_OBJ_DEF * xi_obj_def, XI_OBJ * list ) +{ + XI_LIST_DEF *list_def = xi_obj_def->v.list; + XI_LIST_DATA *list_data; + LM_DEF lm_def; + int i, + min_height; + XinRect rct, + min_rct; + XinWindow itf_win; + BOOLEAN save_or; + + itf_win = list->itf->v.itf->xin_win; + list_data_create( list_def, list ); + list_data = list->v.list; + list_module_def_create( &lm_def, list_def, list ); + if ( list_def->resize_with_window && list->parent + && list->parent->itf->v.itf->xin_win ) + { + XinRect cr; + + XinWindowRectGet( list->parent->itf->v.itf->xin_win, &cr ); + + save_or = xi_obj_def->v.list->one_row_list; + xi_obj_def->v.list->one_row_list = TRUE; + xi_get_def_rect( xi_obj_def, &min_rct ); + xi_obj_def->v.list->one_row_list = save_or; + min_height = min_rct.bottom - min_rct.top; + + lm_def.pixel_height = cr.bottom - lm_def.pnt.v; + if ( lm_def.pixel_width ) + lm_def.pixel_height -= ( int ) xi_get_pref( XI_PREF_SB_HEIGHT ); + lm_def.pixel_height = max( lm_def.pixel_height, min_height ); + + if ( lm_def.pixel_width ) + { + lm_def.pixel_width = cr.right - lm_def.pnt.h - 2 * BORDER_WIDTH; + if ( list_def->scroll_bar ) + lm_def.pixel_width -= ( int ) xi_get_pref( XI_PREF_SB_WIDTH ); + } + } + if ( lm_def.pixel_width ) + { + int min_width; + + min_width = lm_get_width( xi_obj_def, lm_def.pix_char_width, 1, + &lm_def.fixed_columns ); + /* insure minimum size */ + if ( min_width > lm_def.pixel_width ) + lm_def.pixel_width = min_width; + } + + lm_def.list_obj = list; + lm_def.itf_obj = list->itf; + lm_def.parent = ( char * ) list_data; + list_data->width = lm_def.pixel_width; + + /* TODO calculate and set realized_rows_array_len TODO also set nbr_rows, if + * user specified a specific nbr of rows. */ + + list_data->lm = lm_create( itf_win, &lm_def, list_data ); + list_data->scroll_bar_button = list_def->scroll_bar_button; + /* Initialize focus obj data. Use list object for defaults. */ + list_data->focus_cell_array[0] = *list; + list_data->focus_cell_array[0].parent = list; + list_data->focus_cell_array[0].type = XIT_CELL; + list_data->focus_cell_array[0].v.cell.row = + list_data->focus_cell_array[0].v.cell.column = 0; + list_data->focus_cell_array[0].v.cell.is_vert_scrolled = FALSE; + for ( i = 1; i < FOCUS_CELL_ARRAY_LEN; ++i ) + list_data->focus_cell_array[i] = + list_data->focus_cell_array[0]; + list_data->focus_cell = &list_data->focus_cell_array[0]; + list_data->tab_cid = list_def->tab_cid; + list_data->scroll_bar = list_def->scroll_bar; + + xi_add_to_parent_list( list, -1 ); + create_children( xi_obj_def, list, TRUE ); + if ( list_def->scroll_bar ) + { + if ( list_data->sb_win ) + xi_move_list_scroll_bar( list ); + else + { + XinRect rct; + long attrib; + + attrib = lm_get_attrib( list_data->lm, LM_LIST, 0, 0, FALSE ); + xi_get_sb_rect( list, &rct ); + { + XinWindowDef Def; + + MEMCLEAR( Def ); + Def.control_id = list->cid; + Def.type = XinWindowTypeVerticalScrollBar; + Def.p_rect = &rct; + Def.title = ""; + Def.visible = ( BOOLEAN ) ( ( attrib & XI_ATR_VISIBLE ) != 0 ); + Def.enabled = TRUE; + Def.parent = itf_win; + list_data->sb_win = XinWindowCreate( &Def ); + } + if ( !( attrib & XI_ATR_ENABLED ) ) + XinWindowEnable( list_data->sb_win, FALSE ); + xi_get_sb_rect( list, &rct ); + if ( list_data->scroll_bar_button ) + xi_invalidate_rect( list->itf->v.itf->xin_win, + &list_data->sbb_rct ); + } + } + if ( lm_def.pixel_width != 0 ) + { + unsigned long attrib; + + attrib = lm_get_attrib( list_data->lm, LM_LIST, 0, 0, FALSE ); + xi_get_hsb_rect( list, &rct ); + { + XinWindowDef Def; + + MEMCLEAR( Def ); + Def.control_id = list->cid + HSCROLL_CID_CONST; + Def.type = XinWindowTypeHorizontalScrollBar; + Def.p_rect = &rct; + Def.title = ""; + Def.visible = ( BOOLEAN ) ( ( attrib & XI_ATR_VISIBLE ) != 0 ); + Def.enabled = TRUE; + Def.parent = itf_win; + list_data->hsb_win = XinWindowCreate( &Def ); + } + if ( !( attrib & XI_ATR_ENABLED ) ) + XinWindowEnable( list_data->hsb_win, FALSE ); + lm_set_hscroll_range( list_data->lm ); + } + xi_get_rect( list, &rct ); + xi_inflate_rect( &rct, 8 ); + xi_invalidate_rect( itf_win, &rct ); + lm_set_hscroll_range( list->v.list->lm ); + if ( xi_obj_def->v.list->first_vis_column ) + { + XinWindowPaintForce( itf_win ); + xi_hscroll_internal( list, xi_obj_def->v.list->first_vis_column + - lm_def.fixed_columns, 0 ); + } +} + + +/* ------------------------------------------------------------------------ */ +/* xi_create_internal */ +/* ------------------------------------------------------------------------ */ +/* + xi_create_internal performs the following steps: + + 1. Copy the *_DEFs into *_DATAs + 2. Call creation functions for LM, STX, buttons + 3. Initialize event routing +*/ +XI_OBJ * +xi_create_internal( XI_OBJ * parent, XI_OBJ_DEF * xi_obj_def, + BOOLEAN creating_list, BOOLEAN r4_api ) +{ + XI_OBJ *obj; + + if ( !inited ) + xi_init_internal( r4_api ); + + /* object data initialization common to all types */ + obj = ( XI_OBJ * ) xi_tree_malloc( sizeof( XI_OBJ ), ( char * ) parent ); + obj->parent = parent; + obj->cid = xi_obj_def->cid; + obj->type = xi_obj_def->type; + obj->app_data = xi_obj_def->app_data; + obj->app_data2 = xi_obj_def->app_data2; + if (xi_obj_def->help_key != NULL) + { + obj->help_key = (char *)xi_tree_malloc( strlen( xi_obj_def->help_key ) + 1, obj ); + strcpy( obj->help_key, xi_obj_def->help_key ); + } else + obj->help_key = NULL; + + if ( xi_obj_def->type != XIT_ITF ) + { + XinRect rct; + XI_ITF_DATA *itf_data; + + obj->itf = parent->itf; + xi_get_def_rect( xi_obj_def, &rct ); + xi_pu_to_fu( NULL, ( XinPoint * ) & rct, 2 ); + itf_data = obj->itf->v.itf; + itf_data->max_xi_pnt.h = max( itf_data->max_xi_pnt.h, rct.right ); + itf_data->max_xi_pnt.v = max( itf_data->max_xi_pnt.v, rct.bottom ); + } + else + obj->itf = obj; + + switch ( xi_obj_def->type ) + { + case XIT_ITF: + interface_create( xi_obj_def, obj ); + break; + case XIT_CONTAINER: + container_create( xi_obj_def, obj ); + break; + case XIT_RECT: + rectangle_create( xi_obj_def, obj ); + break; + case XIT_LINE: + line_create( xi_obj_def, obj ); + break; + case XIT_BTN: + button_create( xi_obj_def, obj ); + break; + case XIT_FORM: + form_create( xi_obj_def, obj ); + break; + case XIT_FIELD: + field_create( xi_obj_def, obj ); + break; + case XIT_LIST: + list_create( xi_obj_def, obj ); + break; + case XIT_COLUMN: + column_create( xi_obj_def, obj, creating_list ); + break; + case XIT_TEXT: + text_create( xi_obj_def, obj ); + break; + case XIT_GROUP: + group_create( xi_obj_def, obj, creating_list ); + break; + case XIT_CELL: + case XIT_ROW: + default: + XinError( 20016, XinSeverityFatal, 0L ); + } + return obj; +} + +void +xi_close_window_internal( XI_OBJ * itf ) +{ + if ( itf->v.itf->bitmap != NULL ) + xi_bitmap_destroy( itf->v.itf->bitmap ); + XinFontUnmap( xi_get_system_font() ); /* RGM: Unmap hack */ + XinWindowDestroy( itf->v.itf->xin_win ); +} + +static void +xi_delete_internal( XI_OBJ * xi_obj, BOOLEAN recursive ) +{ + XinRect rct; + XI_OBJ_TYPE type = xi_obj->type; + + if ( xi_obj->itf->v.itf->focus_obj == xi_obj ) + xi_obj->itf->v.itf->focus_obj = NULL; + + switch ( type ) + { + case XIT_FIELD: + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &rct ); + stx_delete( xi_obj->v.field->stx, xi_obj->v.field->font_set ); + break; + case XIT_FORM: + case XIT_CONTAINER: + { + XI_OBJ **objlist; + int n; + + /* loop over sub-objects */ + if ( !recursive ) + { + objlist = xi_get_member_list( xi_obj, &n ); + for ( ; n > 0; n--, objlist++ ) + xi_delete_internal( *objlist, TRUE ); + break; + } + } + case XIT_GROUP: + break; + case XIT_ITF: + { + XI_ITF_DATA *itf_data; + + itf_data = xi_obj->v.itf; + if ( itf_data->in_callback ) + { + itf_data->closing = TRUE; + XinWindowEnable( itf_data->xin_win, FALSE ); + } else + xi_close_window_internal( xi_obj ); + return; + } + case XIT_LIST: + { + XI_LIST_DATA *list_data; + + list_data = xi_obj->v.list; + xi_get_rect( xi_obj, &rct ); + if ( list_data->scroll_bar ) + XinWindowDestroy( list_data->sb_win ); + if ( list_data->hsb_win ) + XinWindowDestroy( list_data->hsb_win ); + if ( list_data->font ) + XinFontDestroy( list_data->font ); + xi_inflate_rect( &rct, 8 ); + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &rct ); + if ( !recursive ) + lm_delete( list_data->lm ); + else + { + LM_DATA *lmp = LMP( list_data->lm ); + int focus_row, + focus_column; + BOOLEAN v_scrolled; + if ( lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ) ) + { + lm_focus_remove( lmp, focus_row, focus_column, v_scrolled ); + } + lm_cleanup( list_data->lm ); + } + break; + } + case XIT_COLUMN: + { + XI_LIST_DATA *list_data; + int col_nbr; + BOOLEAN move_hsb; + + list_data = xi_obj->parent->v.list; + col_nbr = xi_obj_to_idx( xi_obj ); + move_hsb = ( col_nbr < ( ( LM_DATA * ) ( list_data->lm ) )->fixed_columns ); + if ( !recursive ) + lm_delete_column( list_data->lm, col_nbr, TRUE ); + if ( list_data->scroll_bar && ( !list_data->width ) ) + xi_move_list_scroll_bar( xi_obj->parent ); + if ( !recursive ) + { + if ( list_data->hsb_win && move_hsb ) + { + list_data->have_hsb_rct = FALSE; + xi_move_list_hscroll_bar( xi_obj->parent ); + } + } + break; + } + case XIT_TEXT: + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &rct ); + if ( xi_obj->v.text->font ) + XinFontDestroy( xi_obj->v.text->font ); + break; + case XIT_RECT: + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &rct ); + if ( xi_obj->v.rect->bitmap != NULL ) + xi_bitmap_destroy( xi_obj->v.rect->bitmap ); + break; + case XIT_LINE: + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &rct ); + break; + case XIT_BTN: + if ( xi_obj->v.btn->btnctl ) + XinWindowDestroy( xi_obj->v.btn->btnctl ); + else + { + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &rct ); + } + if ( xi_obj->v.btn->up_bitmap != NULL ) + xi_bitmap_destroy( xi_obj->v.btn->up_bitmap ); + if ( xi_obj->v.btn->down_bitmap != NULL ) + xi_bitmap_destroy( xi_obj->v.btn->down_bitmap ); + if ( xi_obj->v.btn->disabled_bitmap != NULL ) + xi_bitmap_destroy( xi_obj->v.btn->disabled_bitmap ); + break; + default: + XinError( 20017, XinSeverityFatal, 0L ); + break; + } + if ( !recursive ) + { + xi_remove_from_parent_list( xi_obj ); + if ( type == XIT_COLUMN ) /* an ugly hack */ + { + XI_LIST_DATA *list_data; + + list_data = xi_obj->parent->v.list; + lm_make_rrr_room_pix( ( LM_DATA * ) list_data->lm, 0, FALSE ); + } + xi_tree_free( ( char * ) xi_obj ); + } +} + +void +xi_delete( XI_OBJ * xi_obj ) +{ + xi_delete_internal( xi_obj, FALSE ); +} + +void +xi_move_column_internal( XI_OBJ * column, int position, BOOLEAN in_hscrolling ) +{ + XI_OBJ *list; + XI_LIST_DATA *list_data; + LM_DATA *lm_data; + LM_COLUMN_DATA *col_data; + LM_COLUMN_DEF lm_column_def; + int col_nbr, + i; + BOOLEAN move_hsb = FALSE; + int focus_row, + focus_column; + BOOLEAN v_scrolled; + BOOLEAN redraw_row = FALSE; + + list = column->parent; + list_data = list->v.list; + lm_data = ( LM_DATA * ) list_data->lm; + + i = xi_obj_to_idx( column ); + if ( lm_focus_cell_get( lm_data, &focus_row, &focus_column, &v_scrolled ) ) + if ( focus_column == i && lm_data->row_focus_border ) + redraw_row = TRUE; + if ( list_data->hsb_win ) + if ( i < lm_data->fixed_columns || position < lm_data->fixed_columns ) + move_hsb = TRUE; + if ( position == lm_data->fixed_columns && !in_hscrolling ) + move_hsb = TRUE; + + col_nbr = xi_obj_to_idx( column ); + col_data = lm_data->lm_column_data[col_nbr]; + + MEMCLEAR( lm_column_def ); + lm_column_def.attrib = col_data->attrib; + lm_column_def.position = position; + lm_column_def.pix_width = col_data->pix_width; + lm_column_def.text_size = col_data->text_size; + lm_column_def.heading_text = ( char * ) xi_tree_malloc( + strlen( col_data->heading_text ) + 1, list_data ); + strcpy( lm_column_def.heading_text, col_data->heading_text ); + lm_column_def.center_heading = col_data->center_heading; +#if XIWS != XIWS_WM + lm_column_def.heading_well = col_data->heading_well; + lm_column_def.heading_platform = col_data->heading_platform; + lm_column_def.column_well = col_data->column_well; + lm_column_def.column_platform = col_data->column_platform; +#else + lm_column_def.heading_well = FALSE; + lm_column_def.heading_platform = FALSE; + lm_column_def.column_well = FALSE; + lm_column_def.column_platform = FALSE; +#endif + lm_column_def.icon_rid = col_data->icon_rid; + lm_column_def.icon_x = col_data->icon_x; + lm_column_def.icon_y = col_data->icon_y; + lm_column_def.bitmap = xi_bitmap_copy( col_data->bitmap ); + lm_column_def.vertical_align_center = col_data->vertical_align_center; + lm_column_def.vertical_align_bottom = col_data->vertical_align_bottom; + lm_column_def.wrap_text = col_data->wrap_text; + lm_column_def.wrap_text_scrollbar = col_data->wrap_text_scrollbar; + lm_column_def.cr_ok = col_data->cr_ok; + lm_column_def.var_len_text = col_data->var_len_text; + lm_column_def.auto_tab = col_data->auto_tab; + lm_column_def.icon_mode = col_data->icon_mode; + if ( col_data->font ) + XinFontCopy( &lm_column_def.font, col_data->font ); + + if ( col_nbr == focus_column ) + xi_set_focus( list->itf ); + lm_delete_column( ( LM ) lm_data, col_nbr, FALSE ); + + xi_remove_from_parent_list( column ); + xi_add_to_parent_list( column, lm_column_def.position ); + + lm_create_column( ( LM ) lm_data, &lm_column_def, TRUE, in_hscrolling ); + + /* If column has focus, adjust focus cell value */ + if ( col_nbr == focus_column ) + { + list_data->focus_cell->v.cell.column = position; + xi_set_focus( list_data->focus_cell ); + } + + if ( move_hsb ) + { + list->v.list->have_hsb_rct = FALSE; + xi_move_list_hscroll_bar( column->parent ); + } + lm_set_hscroll_range( ( LM ) lm_data ); + lm_set_hscroll_bar( ( LM ) lm_data ); + if ( redraw_row && !v_scrolled ) + lm_redraw_row( lm_data, focus_row, FALSE ); +} + +void +xi_move_column( XI_OBJ * column, int position ) +{ + XI_OBJ *list; + XI_LIST_DATA *list_data; + LM_DATA *lm_data; + int current_pos; + + list = column->parent; + list_data = list->v.list; + lm_data = ( LM_DATA * ) list_data->lm; + current_pos = xi_obj_to_idx( column ); + xi_move_column_internal( column, position, + ( BOOLEAN ) ( current_pos >= lm_data->fixed_columns ) ); +} + +BOOLEAN +xi_is_auto_tab( XI_OBJ * xi_obj ) +{ + if ( xi_obj->type == XIT_FIELD ) + return ( ( STX_DATA * ) xi_obj->v.field->stx )->auto_tab; + if ( xi_obj->type == XIT_COLUMN ) + return LMP( xi_obj->parent->v.list->lm )-> + lm_column_data[xi_obj_to_idx( xi_obj )]->auto_tab; + return FALSE; +} + +void +xi_init_internal( BOOLEAN r4_api ) +{ + if ( !inited ) + { + xi_set_pref( XI_PREF_R4_API, r4_api ); + inited = TRUE; + xi_init_sysvals( ); + } +} diff --git a/src/xi01/xi_int.h b/src/xi01/xi_int.h new file mode 100644 index 000000000..bbf21bd0e --- /dev/null +++ b/src/xi01/xi_int.h @@ -0,0 +1,40 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#ifndef INCL_XI_INT +#define INCL_XI_INT + +int +xi_scroll_internal( XI_OBJ * xi_obj, int nbr_lines, int percent, + BOOLEAN same_cell ); +void +xi_control_event_scroll( XI_OBJ * xi_obj, int nbr_lines, int percent, + BOOLEAN same_cell ); +void realloc_ptrs( void ***ptrs, int nbr_ptrs, void *parent ); +BOOLEAN +xi_move_focus_internal( XI_OBJ * xi_obj, BOOLEAN make_callbacks, + BOOLEAN next_if_disabled, + int check_for_reenabled ); +XI_OBJ * +xi_search_itf( XI_OBJ * xi_obj, XI_SEARCH_TYPE search_type, + int parm1 ); +XI_OBJ *xi_find_next_obj( XI_OBJ * focus_obj, XI_NEXT_TYPE tab_type, long c ); +void xi_remove_window_from_list( XinWindow win ); +void xi_clear_lasts( void ); +void xi_close_window_internal( XI_OBJ * itf ); +BOOLEAN call_cb( XI_OBJ * itf, XI_EVENT * xiev ); +void xi_hscroll_internal( XI_OBJ * xi_obj, int nbr_lines, int pos ); +void XVT_CALLCONV1 xi_hscroll +XVT_CC_ARGS( ( XI_OBJ * xi_obj, + int nbr_columns ) ); +void xi_draw_field_button( XI_OBJ * xi_obj ); +void xi_field_set_rect_internal( XI_OBJ *xi_obj, XinRect *rect ); +void xi_container_set_rect_internal( XI_OBJ *xi_obj, XinRect *rect ); +void xi_set_rect_internal( XI_OBJ *xi_obj, XinRect *rect ); +#endif diff --git a/src/xi01/xibitmap.c b/src/xi01/xibitmap.c new file mode 100644 index 000000000..0a52305ec --- /dev/null +++ b/src/xi01/xibitmap.c @@ -0,0 +1,284 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#define XI_R3_COMPAT +#include "xi.h" +#include "xiutils.h" + +#if XIWS != XIWS_MAC && XIWS != XIWS_XM && XIWS != XIWS_WXGTK +#include +#endif + +#if XIWS == XIWS_XM || XIWS == XIWS_WXGTK +#include +#endif + +XI_BITMAP * +xi_bitmap_create( char *filename, XI_BITMAP_MODE mode ) +{ + XI_BITMAP *bitmap; + + bitmap = XinMemoryZeroAlloc( sizeof( XI_BITMAP ) ); + if ( filename != NULL ) + { +#if XIWS != XIWS_MAC + if ( access( filename, 0 ) != -1 ) +#endif + bitmap->xin_bitmap = XinBitmapRead( filename ); + if ( bitmap->xin_bitmap == NULL ) + { + XinMemoryFree( bitmap ); + return NULL; + } + } + bitmap->mode = mode; + bitmap->ref_count = 1; + return bitmap; +} + +XI_BITMAP * +xi_bitmap_create_res( short id, XI_BITMAP_MODE mode ) +{ + XI_BITMAP *bitmap; + + bitmap = XinMemoryZeroAlloc( sizeof( XI_BITMAP ) ); + if ( id != 0 ) + { + bitmap->xin_bitmap = XinBitmapReadRes( id ); + if ( bitmap->xin_bitmap == NULL ) + { + XinMemoryFree( bitmap ); + return NULL; + } + } + bitmap->mode = mode; + bitmap->ref_count = 1; + return bitmap; +} + +XI_BITMAP * +xi_bitmap_copy( XI_BITMAP * bitmap ) +{ + if ( bitmap != NULL ) + bitmap->ref_count++; + return bitmap; +} + +void +xi_bitmap_destroy( XI_BITMAP * bitmap ) +{ + if ( bitmap != NULL && --bitmap->ref_count == 0 ) + { + if ( bitmap->xin_bitmap != NULL ) + XinBitmapDestroy( bitmap->xin_bitmap ); + XinMemoryFree( bitmap ); + } +} + +static void +normal_bitmap( XI_BITMAP * bitmap, XinWindow win, XinRect * rct ) +{ + short width, + height; + int x, + y; + XinRect src; + XinRect dest; + int full_width, + full_height; + XinBrush brush; + + if ( bitmap->xin_bitmap == NULL ) + width = height = 0; + else + XinBitmapSizeGet( bitmap->xin_bitmap, &width, &height ); + full_width = rct->right - rct->left; + full_height = rct->bottom - rct->top; + if ( bitmap->hcenter ) + { + if ( width > full_width ) + x = 0; + else + x = ( full_width - width ) / 2; + } + else + x = bitmap->x_offset; + if ( bitmap->vcenter ) + { + if ( height > full_height ) + y = 0; + else + y = ( full_height - height ) / 2; + } + else + y = bitmap->y_offset; + if ( x + width > full_width ) + width = full_width - x; + if ( y + height > full_height ) + height = full_height - y; + if ( bitmap->xin_bitmap != 0 ) + { + dest.top = rct->top + y; + dest.left = rct->left + x; + dest.bottom = dest.top + height; + dest.right = dest.left + width; + src.top = src.left = 0; + src.right = width; + src.bottom = height; + XinWindowBitmapDraw( win, bitmap->xin_bitmap, &dest, &src ); + } + + /* Draw background color around bitmap */ + XinWindowPenSet( win, &hollow_cpen ); + brush.pattern = XinBrushSolid; + brush.fore_color = bitmap->background; + XinWindowBrushSet( win, &brush ); + if ( y > 0 ) + { /* Draw top rectangle */ + dest.top = rct->top; + dest.left = rct->left; + dest.bottom = rct->top + y; + dest.right = rct->right; + xi_draw_rect( win, &dest ); + } + if ( x > 0 ) + { /* Draw left rectangle */ + dest.top = rct->top + y; + dest.left = rct->left; + dest.bottom = dest.top + height; + dest.right = rct->left + x; + xi_draw_rect( win, &dest ); + } + if ( x + width < full_width ) + { /* Draw right rectangle */ + dest.top = rct->top + y; + dest.left = rct->left + x + width; + dest.bottom = dest.top + height; + dest.right = rct->right; + xi_draw_rect( win, &dest ); + } + if ( y + height < full_height ) + { /* Draw bottom rectangle */ + dest.top = rct->top + y + height; + dest.left = rct->left; + dest.bottom = rct->bottom; + dest.right = rct->right; + xi_draw_rect( win, &dest ); + } +} + +static void +resize_bitmap( XI_BITMAP * bitmap, XinWindow win, XinRect * rct ) +{ + short width, + height; + XinRect src; + + XinBitmapSizeGet( bitmap->xin_bitmap, &width, &height ); + src.top = src.left = 0; + src.right = width; + src.bottom = height; + XinWindowBitmapDraw( win, bitmap->xin_bitmap, rct, &src ); +} + +static void +tile_bitmap( XI_BITMAP * bitmap, XinWindow win, XinRect * rct, XinRect * clip_rct, BOOLEAN on_update ) +{ + short width, + height; + XinRect src; + XinRect dest; + int full_width, + full_height; + int x, + y; + + XinBitmapSizeGet( bitmap->xin_bitmap, &width, &height ); + full_width = rct->right - rct->left; + full_height = rct->bottom - rct->top; + src.top = 0; + src.left = 0; + src.bottom = height; + for ( y = 0; y < full_height; y += height ) + { + dest.top = rct->top + y; + if ( clip_rct != NULL ) + { + if ( dest.top > clip_rct->bottom ) + break; + if ( dest.top + height < clip_rct->top ) + continue; + } + if ( y + height > full_height ) + src.bottom = full_height - y; + src.right = width; + for ( x = 0; x < full_width; x += width ) + { + if ( x + width > full_width ) + src.right = full_width - x; + dest.left = rct->left + x; + dest.right = dest.left + src.right; + dest.bottom = dest.top + src.bottom; + if ( clip_rct != NULL ) + { + if ( dest.left > clip_rct->right ) + break; + if ( dest.right < clip_rct->left ) + continue; + } + if ( !on_update || XinWindowPaintNeeds( win, &dest ) ) + XinWindowBitmapDraw( win, bitmap->xin_bitmap, &dest, &src ); + } + } +} + +void +xi_bitmap_draw( XI_BITMAP * bitmap, XinWindow win, XinRect * rct, + XinRect * clip_rct, BOOLEAN in_paint_event ) +{ + XI_BITMAP_MODE mode; + + if ( bitmap == NULL ) + return; + + if ( bitmap->xin_bitmap == NULL ) + mode = XI_BITMAP_NORMAL; + else + mode = bitmap->mode; + XinWindowClipSet( win, clip_rct ); + switch ( mode ) + { + case XI_BITMAP_NORMAL: + normal_bitmap( bitmap, win, rct ); + break; + case XI_BITMAP_RESIZE: + resize_bitmap( bitmap, win, rct ); + break; + case XI_BITMAP_TILE: + tile_bitmap( bitmap, win, rct, clip_rct, in_paint_event ); + break; + } +} + +void +xi_bitmap_size_get( XI_BITMAP * bitmap, short *width, short *height ) +{ + if ( bitmap != NULL && bitmap->xin_bitmap != NULL ) + XinBitmapSizeGet( bitmap->xin_bitmap, width, height ); +} + +BOOLEAN +xi_bitmap_draw_all_on_resize( XI_BITMAP * bitmap ) +{ + if ( bitmap == NULL || bitmap->xin_bitmap == NULL ) + return FALSE; + return ( ( bitmap->mode == XI_BITMAP_NORMAL && ( bitmap->vcenter || bitmap->hcenter ) ) + || bitmap->mode == XI_BITMAP_RESIZE ); +} diff --git a/src/xi01/xicf.c b/src/xi01/xicf.c new file mode 100644 index 000000000..35a0cde03 --- /dev/null +++ b/src/xi01/xicf.c @@ -0,0 +1,1344 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#define XI_R3_COMPAT +#include "xi.h" +#include "xiutils.h" +#include "xitext.h" +#include "xistx.h" +#include "xilm.h" +#include "xilmst.h" + +/* ERROR CODES 20101-20112 */ + +void realloc_ptrs( void ***ptrs, int nbr_ptrs, void *parent ); + +#define XI_PTR_INC 10 + +/* + realloc_ptrs: reallocate an array of pointers by adding one to + the current number of pointers. This function will attempt to + reallocate by blocks to improve performance. +*/ +void +realloc_ptrs( void ***ptrs, int nbr_ptrs, void *parent ) +{ + int cur_nbr_alloc; + int nbr_alloc; + + cur_nbr_alloc = ( ( nbr_ptrs - 1 ) / XI_PTR_INC + 1 ) * XI_PTR_INC; + nbr_alloc = ( nbr_ptrs / XI_PTR_INC + 1 ) * XI_PTR_INC; + + if ( *ptrs == NULL ) + { + *ptrs = ( void ** ) + xi_tree_malloc( sizeof( void * ) * nbr_alloc, parent ); + } + else + { + if ( cur_nbr_alloc != nbr_alloc ) + { + *ptrs = ( void ** ) + xi_tree_realloc( *ptrs, sizeof( void * ) * nbr_alloc ); + } + } +} + +XI_OBJ_DEF * +xi_create_itf_def( int cid, XI_EVENT_HANDLER xi_eh, XinRect * rctp, char *title, + long app_data ) +{ + XI_OBJ_DEF *itf; + XI_ITF_DEF *xi_id; + + itf = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), NULL ); + itf->type = XIT_ITF; + itf->cid = cid; + itf->v.itf = xi_id = ( XI_ITF_DEF * ) xi_tree_malloc( sizeof( XI_ITF_DEF ), itf ); + itf->app_data = app_data; + xi_id->xi_eh = xi_eh; + itf->v.itf->use_xil_win = FALSE; + if ( rctp ) + { + xi_id->rctp = ( XinRect * ) xi_tree_malloc( sizeof( XinRect ), itf->v.itf ); + *( xi_id->rctp ) = *rctp; + } + else + xi_id->rctp = NULL; + xi_id->title = title; + xi_id->ctl_close = TRUE; + xi_id->ctl_iconized = FALSE; + xi_id->ctl_iconizable = FALSE; + xi_id->maximized = FALSE; + xi_id->visible = TRUE; + xi_id->enabled = TRUE; + xi_id->parent = XI_NULL_WINDOW; + xi_id->border_style_set = FALSE; + xi_id->menu = NULL; + xi_id->icon_rid = 0; + itf->nbr_children = 0; + itf->children = NULL; + return itf; +} + +XI_OBJ_DEF * +xi_add_form_def( XI_OBJ_DEF * itf, int cid, int tab_cid ) +{ + XI_OBJ_DEF *form; + XI_FORM_DEF *xi_fd; + + form = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), itf ); + form->type = XIT_FORM; + form->cid = cid; + form->parent = itf; + form->nbr_children = 0; + form->children = NULL; + form->v.form = xi_fd = ( XI_FORM_DEF * ) xi_tree_malloc( sizeof( XI_FORM_DEF ), form ); + xi_fd->tab_cid = tab_cid; + if ( itf != NULL ) + { + if ( itf->type != XIT_ITF ) + XinError( 20101, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &itf->children, itf->nbr_children, itf ); + itf->children[itf->nbr_children] = form; + itf->nbr_children++; + } + return form; +} + +XI_OBJ_DEF * +xi_add_line_def( XI_OBJ_DEF * itf, int cid, XinPoint * pnt1, + XinPoint * pnt2, unsigned long attrib, XinColor fore_color, + XinColor back_color, BOOLEAN well ) +{ + XI_OBJ_DEF *line_obj; + XI_LINE_DEF *xi_ld; + + line_obj = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), itf ); + line_obj->type = XIT_LINE; + line_obj->cid = cid; + line_obj->parent = itf; + line_obj->v.line = xi_ld = ( XI_LINE_DEF * ) xi_tree_malloc( sizeof( XI_LINE_DEF ), line_obj ); + xi_ld->pnt1 = *pnt1; + xi_ld->pnt2 = *pnt2; + xi_ld->fore_color = fore_color; + xi_ld->back_color = back_color; + xi_ld->well = well; + xi_ld->attrib = attrib; + if ( itf != NULL ) + { + if ( itf->type != XIT_ITF ) + XinError( 20108, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &itf->children, itf->nbr_children, itf ); + itf->children[itf->nbr_children] = line_obj; + itf->nbr_children++; + } + return line_obj; +} + +XI_OBJ_DEF * +xi_add_list_def( XI_OBJ_DEF * itf, int cid, int v, int h, +int height, unsigned long attrib, XinColor enabled_color, XinColor back_color, +XinColor disabled_color, XinColor disabled_back_color, XinColor active_color, + int tab_cid ) +{ + XI_OBJ_DEF *list; + XI_LIST_DEF *xi_ld; + + list = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), itf ); + list->type = XIT_LIST; + list->cid = cid; + list->parent = itf; + list->nbr_children = 0; + list->children = NULL; + list->v.list = xi_ld = ( XI_LIST_DEF * ) xi_tree_malloc( sizeof( XI_LIST_DEF ), list ); + xi_ld->xi_pnt.v = v; + xi_ld->xi_pnt.h = h; + xi_ld->height = height; + xi_ld->attrib = attrib; + xi_ld->enabled_color = enabled_color; + xi_ld->back_color = back_color; + xi_ld->disabled_color = disabled_color; + xi_ld->disabled_back_color = disabled_back_color; + xi_ld->active_color = active_color; + xi_ld->active_back_color = back_color; + xi_ld->tab_cid = tab_cid; + if ( itf != NULL ) + { + if ( itf->type != XIT_ITF ) + XinError( 20102, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &itf->children, itf->nbr_children, itf ); + itf->children[itf->nbr_children] = list; + itf->nbr_children++; + } + return list; +} + +XI_OBJ_DEF * +xi_add_column_def( XI_OBJ_DEF * list, int cid, + unsigned long attrib, int sort_number, int width, int text_size, + char *heading_text ) +{ + XI_OBJ_DEF *column; + XI_COLUMN_DEF *xi_cd; + + column = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), list ); + column->type = XIT_COLUMN; + column->cid = cid; + column->parent = list; + column->v.column = xi_cd = ( XI_COLUMN_DEF * ) xi_tree_malloc( sizeof( XI_COLUMN_DEF ), column ); + xi_cd->attrib = attrib; + xi_cd->sort_number = sort_number; + xi_cd->width = width; + xi_cd->text_size = text_size; + xi_cd->heading_text = ( char * ) xi_tree_malloc( strlen( heading_text ) + 1, column ); + strcpy( xi_cd->heading_text, heading_text ); + if ( list != NULL ) + { + if ( list->type != XIT_LIST ) + XinError( 20103, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &list->children, list->nbr_children, list ); + list->children[list->nbr_children] = column; + list->nbr_children++; + } + return column; +} + +XI_OBJ_DEF * +xi_add_field_def( XI_OBJ_DEF * form, int cid, + int v, int h, int field_width, unsigned long attrib, + int tab_cid, int text_size, XinColor enabled_color, + XinColor back_color, XinColor disabled_color, XinColor disabled_back_color, + XinColor active_color ) +{ + XI_OBJ_DEF *field; + XI_FIELD_DEF *xi_fd; + + if ( text_size <= 0 ) + XinError( 20112, XinSeverityFatal, 0L ); + field = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), form ); + field->type = XIT_FIELD; + field->cid = cid; + field->parent = form; + field->v.field = xi_fd = ( XI_FIELD_DEF * ) xi_tree_malloc( sizeof( XI_FIELD_DEF ), field ); + xi_fd->pnt.h = h; + xi_fd->pnt.v = v; + xi_fd->field_width = field_width; + xi_fd->attrib = attrib; + xi_fd->tab_cid = tab_cid; + xi_fd->text_size = text_size; + xi_fd->back_color = back_color; + xi_fd->enabled_color = enabled_color; + xi_fd->disabled_color = disabled_color; + xi_fd->disabled_back_color = disabled_back_color; + xi_fd->active_color = active_color; + xi_fd->active_back_color = back_color; + if ( form != NULL ) + { + if ( form->type != XIT_FORM ) + XinError( 20104, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &form->children, + form->nbr_children, form ); + form->children[form->nbr_children] = field; + form->nbr_children++; + } + return field; +} + +XI_OBJ_DEF * +xi_add_container_def( XI_OBJ_DEF * itf, int cid, + XinRect * xi_rct, XI_CONTAINER_ORIENTATION orientation, int tab_cid ) +{ + XI_OBJ_DEF *container; + XI_CONTAINER_DEF *xi_cd; + + container = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), itf ); + container->type = XIT_CONTAINER; + container->cid = cid; + container->parent = itf; + container->nbr_children = 0; + container->children = NULL; + container->v.container = xi_cd = + ( XI_CONTAINER_DEF * ) xi_tree_malloc( sizeof( XI_CONTAINER_DEF ), container ); + xi_cd->xi_rct = *xi_rct; + xi_cd->orientation = orientation; + xi_cd->tab_cid = tab_cid; + if ( itf != NULL ) + { + if ( itf->type != XIT_ITF ) + XinError( 20105, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &itf->children, itf->nbr_children, itf ); + itf->children[itf->nbr_children] = container; + itf->nbr_children++; + } + return container; +} + +XI_OBJ_DEF * +xi_add_button_def( XI_OBJ_DEF * parent, int cid, XinRect * rct, + unsigned long attrib, char *text, int tab_cid ) +{ + XI_OBJ_DEF *btn; + XI_BTN_DEF *xi_bd; + + btn = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), parent ); + btn->type = XIT_BTN; + btn->cid = cid; + btn->parent = parent; + btn->v.btn = xi_bd = ( XI_BTN_DEF * ) xi_tree_malloc( sizeof( XI_BTN_DEF ), btn ); + if ( rct != NULL ) + xi_bd->xi_rct = *rct; + xi_bd->attrib = attrib; + xi_bd->text = ( char * ) xi_tree_malloc( strlen( text ) + 1, btn ); + strcpy( xi_bd->text, text ); + xi_bd->tab_cid = tab_cid; + if ( parent != NULL ) + { + if ( !( parent->type == XIT_ITF || parent->type == XIT_CONTAINER ) ) + XinError( 20106, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &parent->children, parent->nbr_children, parent ); + parent->children[parent->nbr_children] = btn; + parent->nbr_children++; + } + return btn; +} + +XI_OBJ_DEF * +xi_add_text_def( XI_OBJ_DEF * itf, int cid, XinRect * rct, + unsigned long attrib, char *text ) +{ + XI_OBJ_DEF *text_obj; + XI_TEXT_DEF *xi_td; + + text_obj = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), itf ); + text_obj->type = XIT_TEXT; + text_obj->cid = cid; + text_obj->parent = itf; + text_obj->v.text = xi_td = ( XI_TEXT_DEF * ) xi_tree_malloc( sizeof( XI_TEXT_DEF ), text_obj ); + xi_td->xi_rct = *rct; + xi_td->attrib = attrib; + xi_td->text = ( char * ) xi_tree_malloc( strlen( text ) + 1, text_obj ); + strcpy( xi_td->text, text ); + if ( itf != NULL ) + { + if ( itf->type != XIT_ITF ) + XinError( 20107, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &itf->children, itf->nbr_children, itf ); + itf->children[itf->nbr_children] = text_obj; + itf->nbr_children++; + } + return text_obj; +} + +XI_OBJ_DEF * +xi_add_rect_def( XI_OBJ_DEF * itf, int cid, XinRect * rct, + unsigned long attrib, XinColor fore_color, XinColor back_color ) +{ + XI_OBJ_DEF *rect_obj; + XI_RECT_DEF *xi_rd; + + rect_obj = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), itf ); + rect_obj->type = XIT_RECT; + rect_obj->cid = cid; + rect_obj->parent = itf; + rect_obj->v.rect = xi_rd = ( XI_RECT_DEF * ) xi_tree_malloc( sizeof( XI_RECT_DEF ), rect_obj ); + xi_rd->xi_rct = *rct; + xi_rd->fore_color = fore_color; + xi_rd->back_color = back_color; + xi_rd->attrib = attrib; + if ( itf != NULL ) + { + if ( itf->type != XIT_ITF ) + XinError( 20111, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &itf->children, itf->nbr_children, itf ); + itf->children[itf->nbr_children] = rect_obj; + itf->nbr_children++; + } + return rect_obj; +} + +XI_OBJ_DEF * +xi_add_group_def( XI_OBJ_DEF * itf, int cid, int nbr_cids, + int *cid_list ) +{ + XI_OBJ_DEF *group; + XI_GROUP_DEF *xi_gd; + + group = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), itf ); + group->type = XIT_GROUP; + group->cid = cid; + group->parent = itf; + group->v.group = xi_gd = ( XI_GROUP_DEF * ) xi_tree_malloc( sizeof( XI_GROUP_DEF ), group ); + xi_gd->nbr_cids = nbr_cids; + if ( nbr_cids <= 0 ) + XinError( 20109, XinSeverityFatal, 0L ); + xi_gd->cids = ( int * ) xi_tree_malloc( sizeof( int ) * nbr_cids, xi_gd ); + memcpy( ( char * ) xi_gd->cids, ( char * ) cid_list, + ( size_t ) ( sizeof( int ) * nbr_cids ) ); + if ( itf != NULL ) + { + if ( itf->type != XIT_ITF ) + XinError( 20110, XinSeverityFatal, 0L ); + realloc_ptrs( ( void *** ) &itf->children, itf->nbr_children, itf ); + itf->children[itf->nbr_children] = group; + itf->nbr_children++; + } + return group; +} + +XI_OBJ_DEF * +xi_get_column_def( XI_OBJ * column_obj, + LM_COLUMN_DATA * lmcdp, int index, + void *parent ) +{ + XI_OBJ_DEF *column; + XI_COLUMN_DEF *xi_cd; + + column = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), parent ); + column->type = XIT_COLUMN; + column->cid = column_obj->cid; + column->app_data = column_obj->app_data; + column->v.column = xi_cd = ( XI_COLUMN_DEF * ) xi_tree_malloc( + sizeof( XI_COLUMN_DEF ), column ); + xi_cd->attrib = lmcdp->attrib; + xi_cd->sort_number = index * 10; + if ( xi_get_xil_pref( column_obj->itf ) ) + { + xi_cd->pixel_width = lmcdp->pix_width; + xi_cd->width = lmcdp->width; + } + else + { + xi_cd->pixel_width = lmcdp->pix_width; + xi_cd->width = lmcdp->width * XI_FU_MULTIPLE; + } + xi_cd->text_size = lmcdp->text_size; + xi_cd->heading_text = ( char * ) xi_tree_malloc( strlen( + lmcdp->heading_text ) + 1, column ); + strcpy( xi_cd->heading_text, lmcdp->heading_text ); + xi_cd->center_heading = lmcdp->center_heading; + xi_cd->heading_well = lmcdp->heading_well; + xi_cd->heading_platform = lmcdp->heading_platform; + xi_cd->column_well = lmcdp->column_well; + xi_cd->column_platform = lmcdp->column_platform; + if ( lmcdp->font ) + { + /* Make a copy because lmcdp->font will be destroyed with the column */ + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &xi_cd->font, lmcdp->font ); + xi_cd->font_id = NULL; + } +#ifdef XI_USE_XVT + else + { + XinFontCopy( &xi_cd->font, lmcdp->font ); + xi_cd->font_id = XinFontXvtConvertBack( xi_cd->font ); + xi_cd->font = NULL; + } +#endif + } + xi_cd->icon_rid = lmcdp->icon_rid; + xi_cd->icon_x = lmcdp->icon_x; + xi_cd->icon_y = lmcdp->icon_y; + xi_cd->bitmap = xi_bitmap_copy( lmcdp->bitmap ); + xi_cd->size_rows = lmcdp->size_rows; + xi_cd->suppress_update_heading = lmcdp->suppress_update_heading; + xi_cd->suppress_update_cells = lmcdp->suppress_update_cells; + xi_cd->vertical_align_center = lmcdp->vertical_align_center; + xi_cd->vertical_align_bottom = lmcdp->vertical_align_bottom; + xi_cd->wrap_text = lmcdp->wrap_text; + xi_cd->wrap_text_scrollbar = lmcdp->wrap_text_scrollbar; + xi_cd->cr_ok = lmcdp->cr_ok; + xi_cd->var_len_text = lmcdp->var_len_text; + xi_cd->auto_tab = lmcdp->auto_tab; + xi_cd->icon_mode = lmcdp->icon_mode; + return column; +} + +XI_OBJ_DEF * +xi_get_list_def( XI_OBJ * list_obj ) +{ + XI_OBJ_DEF *list; + XI_LIST_DEF *xi_ld; + XI_LIST_DATA *list_data; + LM_DATA *lmp; + XinPoint p; + int i; + int nbr_recs; + long *recs; + + list_data = list_obj->v.list; + lmp = ( LM_DATA * ) list_data->lm; + list = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), NULL ); + list->type = XIT_LIST; + list->cid = list_obj->cid; + list->app_data = list_obj->app_data; + list->v.list = xi_ld = ( XI_LIST_DEF * ) xi_tree_malloc( sizeof( XI_LIST_DEF ), list ); + xi_ld->xi_pnt = list_data->xi_pnt; + xi_ld->height = list_data->height; + xi_ld->pixel_height = lmp->pixel_height; + xi_ld->attrib = lmp->attrib; + xi_ld->enabled_color = lmp->enabled_color; + xi_ld->back_color = lmp->back_color; + xi_ld->disabled_color = lmp->disabled_color; + xi_ld->disabled_back_color = lmp->disabled_back_color; + xi_ld->active_color = lmp->active_color; + xi_ld->active_back_color = lmp->active_back_color; + xi_ld->white_space_color = lmp->white_space_color; + xi_ld->rule_color = lmp->rule_color; + xi_ld->tab_cid = list_data->tab_cid; + xi_ld->no_heading = lmp->no_heading; + xi_ld->one_row_list = list_data->one_row_list; + xi_ld->scroll_bar = list_data->scroll_bar; + xi_ld->sizable_columns = lmp->sizable_columns; + xi_ld->movable_columns = lmp->movable_columns; + xi_ld->scroll_bar_button = list_data->scroll_bar_button; + xi_ld->fixed_columns = lmp->fixed_columns; + xi_ld->resize_with_window = lmp->resize_with_window; + xi_ld->horz_sync_list = lmp->horz_sync_list; + xi_ld->vert_sync_list = lmp->vert_sync_list; + xi_ld->row_focus_border = lmp->row_focus_border; + xi_ld->row_focus_border_color = lmp->row_focus_border_color; + xi_ld->max_lines_in_cell = lmp->max_lines_in_cell; + xi_ld->single_select = lmp->single_select; + if ( xi_get_xil_pref( list_obj->parent ) ) + xi_ld->width = lmp->pixel_width; + else + { + p.h = lmp->pixel_width; + xi_pu_to_fu( list_obj->itf, &p, 1 ); + xi_ld->width = p.h; + } + xi_ld->min_cell_height = lmp->min_cell_height; + xi_ld->min_heading_height = lmp->min_heading_height; + xi_ld->no_horz_lines = lmp->no_horz_lines; + xi_ld->no_vert_lines = lmp->no_vert_lines; + xi_ld->drop_and_delete = lmp->drop_and_delete; + xi_ld->select_cells = lmp->select_cells; + xi_ld->get_all_records = lmp->get_all_records; + if ( lmp->font ) + { + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &xi_ld->font, lmp->font ); + xi_ld->font_id = NULL; + } +#ifdef XI_USE_XVT + else + { + XinFontCopy( &xi_ld->font, lmp->font ); + xi_ld->font_id = XinFontXvtConvertBack( xi_ld->font ); + xi_ld->font = NULL; + } +#endif + } + + recs = lm_get_list_info( list_data->lm, &nbr_recs ); + if ( nbr_recs > 0 ) + { + XI_EVENT xiev; + XI_OBJ *itf; + + itf = list_obj->itf; + MEMCLEAR( xiev ); + xiev.type = XIE_GET_PERCENT; + xiev.v.get_percent.record = recs[0]; + xiev.v.get_percent.list = list_obj; + ( *( XI_EVENT_HANDLER ) itf->v.itf->xi_eh ) ( itf, &xiev ); + xi_ld->start_percent = xiev.v.get_percent.percent; + } + xi_ld->first_vis_column = lmp->first_vis; + + list->nbr_children = lmp->nbr_columns; + realloc_ptrs( ( void *** ) &list->children, list->nbr_children, + list ); + for ( i = 0; i < list->nbr_children; ++i ) + list->children[i] = xi_get_column_def( list_obj->children[i], + lmp->lm_column_data[i], i, list ); + return list; +} + +XI_OBJ_DEF * +xi_get_column_def2( XI_OBJ * column_obj ) +{ + XI_OBJ *list_obj; + LM_DATA *lmp; + int i; + + list_obj = column_obj->parent; + lmp = ( LM_DATA * ) list_obj->v.list->lm; + + for ( i = 0; i < list_obj->nbr_children; ++i ) + if ( list_obj->children[i] == column_obj ) + return xi_get_column_def( column_obj, lmp->lm_column_data[i], i, NULL ); + return 0; +} + +XI_OBJ_DEF * +xi_get_def( XI_OBJ * xi_obj ) +{ + switch ( xi_obj->type ) + { +case XIT_LIST: + return xi_get_list_def( xi_obj ); + case XIT_COLUMN: + return xi_get_column_def2( xi_obj ); + case XIT_FIELD: + { + XI_OBJ_DEF *field; + XI_FIELD_DEF *xi_fd; + XI_FIELD_DATA *field_data; + STX_DATA *stxp; + + field_data = xi_obj->v.field; + stxp = ( STX_DATA * ) field_data->stx; + field = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), NULL ); + field->type = XIT_FIELD; + field->cid = xi_obj->cid; + field->app_data = xi_obj->app_data; + field->v.field = xi_fd = + ( XI_FIELD_DEF * ) xi_tree_malloc( sizeof( XI_FIELD_DEF ), field ); + xi_fd->xi_rct = field_data->xi_rct; + xi_fd->pnt = field_data->xi_pnt; + xi_fd->field_width = field_data->field_width; + xi_fd->var_len_text = field_data->var_len_text; + xi_fd->attrib = stxp->attrib; + xi_fd->tab_cid = field_data->tab_cid; + xi_fd->text_size = stxp->text_size; + xi_fd->back_color = stxp->back_color; + xi_fd->enabled_color = stxp->enabled_color; + xi_fd->disabled_color = stxp->disabled_color; + xi_fd->disabled_back_color = stxp->disabled_back_color; + xi_fd->active_color = stxp->active_color; + xi_fd->active_back_color = stxp->active_back_color; + xi_fd->hilight_color = stxp->hilight_color; + xi_fd->shadow_color = stxp->shadow_color; + xi_fd->button = field_data->button; + xi_fd->button_on_left = field_data->button_on_left; + xi_fd->no_button_space = field_data->no_button_space; + xi_fd->icon_rid = field_data->icon_rid; + xi_fd->button_bitmap = xi_bitmap_copy( field_data->button_bitmap ); + xi_fd->well = field_data->well; + xi_fd->platform = field_data->platform; + xi_fd->mnemonic = field_data->mnemonic; + if ( field_data->font_set ) + { + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &xi_fd->font, stxp->font ); + xi_fd->font_id = NULL; + } +#ifdef XI_USE_XVT + else + { + XinFontCopy( &xi_fd->font, stxp->font ); + xi_fd->font_id = XinFontXvtConvertBack( xi_fd->font ); + xi_fd->font = NULL; + } +#endif + } + return field; + } + case XIT_TEXT: + { + XI_OBJ_DEF *text; + XI_TEXT_DEF *xi_td; + XI_TEXT_DATA *text_data; + + text_data = xi_obj->v.text; + text = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), NULL ); + text->type = XIT_TEXT; + text->cid = xi_obj->cid; + text->app_data = xi_obj->app_data; + text->v.text = xi_td = + ( XI_TEXT_DEF * ) xi_tree_malloc( sizeof( XI_TEXT_DEF ), text ); + xi_td->xi_rct = text_data->xi_rct; + xi_td->attrib = text_data->attrib; + if ( text_data->text ) + { + xi_td->text = ( char * ) xi_tree_malloc( strlen( text_data->text ) + 1, + xi_td ); + strcpy( xi_td->text, text_data->text ); + } + xi_td->fore_color = text_data->fore_color; + xi_td->back_color = text_data->back_color; + xi_td->mnemonic = text_data->mnemonic; + xi_td->mnemonic_instance = text_data->mnemonic_instance; + if ( text_data->font ) + { + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &xi_td->font, text_data->font ); + xi_td->font_id = NULL; + } +#ifdef XI_USE_XVT + else + { + XinFontCopy( &xi_td->font, text_data->font ); + xi_td->font_id = XinFontXvtConvertBack( xi_td->font ); + xi_td->font = NULL; + } +#endif + } + return text; + } + case XIT_BTN: + { + XI_OBJ_DEF *btn; + XI_BTN_DEF *xi_bd; + XI_BTN_DATA *btn_data; + + btn_data = xi_obj->v.btn; + btn = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), NULL ); + btn->type = XIT_BTN; + btn->cid = xi_obj->cid; + btn->app_data = xi_obj->app_data; + btn->v.btn = xi_bd = + ( XI_BTN_DEF * ) xi_tree_malloc( sizeof( XI_BTN_DEF ), btn ); + xi_bd->xi_rct = btn_data->xi_rct; + xi_bd->pixel_rect = btn_data->rct; + xi_bd->attrib = btn_data->attrib; + if ( btn_data->text ) + { + xi_bd->text = ( char * ) xi_tree_malloc( strlen( btn_data->text ) + 1, + xi_bd ); + strcpy( xi_bd->text, btn_data->text ); + } + xi_bd->tab_cid = btn_data->tab_cid; + xi_bd->dflt = btn_data->dflt; + xi_bd->cancel = btn_data->cancel; + xi_bd->down_icon_rid = btn_data->down_icon_rid; + xi_bd->up_icon_rid = btn_data->up_icon_rid; + xi_bd->disabled_icon_rid = btn_data->disabled_icon_rid; + xi_bd->icon_x = btn_data->icon_x; + xi_bd->icon_y = btn_data->icon_y; + xi_bd->up_bitmap = xi_bitmap_copy( btn_data->up_bitmap ); + xi_bd->down_bitmap = xi_bitmap_copy( btn_data->down_bitmap ); + xi_bd->disabled_bitmap = xi_bitmap_copy( btn_data->disabled_bitmap ); + xi_bd->checked = btn_data->checked; + xi_bd->fore_color = btn_data->fore_color; + xi_bd->draw_as = btn_data->draw_as; + xi_bd->drawable = btn_data->drawable; + xi_bd->mnemonic = btn_data->mnemonic; + xi_bd->mnemonic_instance = btn_data->mnemonic_instance; + if ( btn_data->font ) + { + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &xi_bd->font, btn_data->font ); + xi_bd->font_id = NULL; + } +#ifdef XI_USE_XVT + else + { + XinFontCopy( &xi_bd->font, btn_data->font ); + xi_bd->font_id = XinFontXvtConvertBack( xi_bd->font ); + xi_bd->font = NULL; + } +#endif + } + return btn; + } + case XIT_LINE: + { + XI_OBJ_DEF *line; + XI_LINE_DEF *xi_ld; + XI_LINE_DATA *line_data; + + line_data = xi_obj->v.line; + line = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), NULL ); + line->type = XIT_LINE; + line->cid = xi_obj->cid; + line->app_data = xi_obj->app_data; + line->v.line = xi_ld = + ( XI_LINE_DEF * ) xi_tree_malloc( sizeof( XI_LINE_DEF ), line ); + xi_ld->pnt1 = line_data->xi_pnt1; + xi_ld->pnt2 = line_data->xi_pnt2; + xi_ld->pixel_pnt1 = line_data->pnt1; + xi_ld->pixel_pnt2 = line_data->pnt2; + xi_ld->fore_color = line_data->fore_color; + xi_ld->back_color = line_data->back_color; + xi_ld->well = line_data->well; + xi_ld->attrib = line_data->attrib; + return line; + } + case XIT_RECT: + { + XI_OBJ_DEF *rect; + XI_RECT_DEF *xi_rd; + XI_RECT_DATA *rect_data; + + rect_data = xi_obj->v.rect; + rect = ( XI_OBJ_DEF * ) xi_tree_malloc( sizeof( XI_OBJ_DEF ), NULL ); + rect->type = XIT_RECT; + rect->cid = xi_obj->cid; + rect->app_data = xi_obj->app_data; + rect->v.rect = xi_rd = + ( XI_RECT_DEF * ) xi_tree_malloc( sizeof( XI_RECT_DEF ), rect ); + xi_rd->xi_rct = rect_data->xi_rct; + xi_rd->pixel_rect = rect_data->rct; + xi_rd->fore_color = rect_data->fore_color; + xi_rd->back_color = rect_data->back_color; + xi_rd->hilight_color = rect_data->hilight_color; + xi_rd->shadow_color = rect_data->shadow_color; + xi_rd->well = rect_data->well; + xi_rd->attrib = rect_data->attrib; + xi_rd->bitmap = xi_bitmap_copy( rect_data->bitmap ); + return rect; + } + default: + break; + } + return NULL; +} + +/*--------------------------------------------------------------------------*/ +/* xi_def_free_internal */ +/*--------------------------------------------------------------------------*/ +static void +xi_def_free_internal( XI_OBJ_DEF* obj_def ) +{ + int num; + + switch ( obj_def->type ) + { + case XIT_ITF: + if ( obj_def->v.itf->font != NULL ) + XinFontDestroy( obj_def->v.itf->font ); +#ifdef XI_USE_XVT + else if ( obj_def->v.itf->font_id != NULL ) + XinFontXvtDestroy( obj_def->v.itf->font_id ); +#endif + xi_bitmap_destroy( obj_def->v.itf->bitmap ); + break; + case XIT_LIST: + if ( obj_def->v.list->font != NULL ) + XinFontDestroy( obj_def->v.list->font ); +#ifdef XI_USE_XVT + else if ( obj_def->v.list->font_id != NULL ) + XinFontXvtDestroy( obj_def->v.list->font_id ); +#endif + break; + case XIT_COLUMN: + if ( obj_def->v.column->font != NULL ) + XinFontDestroy( obj_def->v.column->font ); +#ifdef XI_USE_XVT + else if ( obj_def->v.column->font_id != NULL ) + XinFontXvtDestroy( obj_def->v.column->font_id ); +#endif + xi_bitmap_destroy( obj_def->v.column->bitmap ); + break; + case XIT_FIELD: + if ( obj_def->v.field->font != NULL ) + XinFontDestroy( obj_def->v.field->font ); +#ifdef XI_USE_XVT + else if ( obj_def->v.field->font_id != NULL ) + XinFontXvtDestroy( obj_def->v.field->font_id ); +#endif + xi_bitmap_destroy( obj_def->v.field->button_bitmap ); + break; + case XIT_TEXT: + if ( obj_def->v.text->font != NULL ) + XinFontDestroy( obj_def->v.text->font ); +#ifdef XI_USE_XVT + else if ( obj_def->v.text->font_id != NULL ) + XinFontXvtDestroy( obj_def->v.text->font_id ); +#endif + break; + case XIT_BTN: + { + XI_BTN_DEF* btn_def = obj_def->v.btn; + + if ( btn_def->font != NULL ) + XinFontDestroy( btn_def->font ); +#ifdef XI_USE_XVT + else if ( btn_def->font_id != NULL ) + XinFontXvtDestroy( btn_def->font_id ); +#endif + xi_bitmap_destroy( btn_def->down_bitmap ); + xi_bitmap_destroy( btn_def->up_bitmap ); + xi_bitmap_destroy( btn_def->disabled_bitmap ); + break; + } + case XIT_RECT: + xi_bitmap_destroy( obj_def->v.rect->bitmap ); + break; + default: + break; + } + for ( num = 0; num < obj_def->nbr_children; num++ ) + xi_def_free_internal( obj_def->children[ num ] ); +} + +/*--------------------------------------------------------------------------*/ +/* xi_def_free */ +/*--------------------------------------------------------------------------*/ +void +xi_def_free( XI_OBJ_DEF* obj_def ) +{ + xi_def_free_internal( obj_def ); + xi_tree_free( obj_def ); +} + +/*--------------------------------------------------------------------------*/ +/* get_button_def_rect */ +/*--------------------------------------------------------------------------*/ +static void +get_button_def_rect( XinFont * font, XI_OBJ_DEF * obj_def, + XinRect * rect ) +{ + *rect = obj_def->v.btn->pixel_rect; + if ( rect->right == 0 && rect->left == 0 && rect->top == 0 + && rect->bottom == 0 ) + { + *rect = obj_def->v.btn->xi_rct; + xi_fu_to_pu_font( font, ( XinPoint * ) rect, 2 ); + } + if ( rect->top == rect->bottom ) + rect->bottom = rect->top + ( int ) xi_get_pref( XI_PREF_BUTTON_HEIGHT ); +} + +/*--------------------------------------------------------------------------*/ +/* get_container_def_rect */ +/*--------------------------------------------------------------------------*/ +static void +get_container_def_rect( XinFont * font, XI_OBJ_DEF * obj_def, + XinRect * rect ) +{ + *rect = obj_def->v.container->pixel_rect; + if ( !rect->right && !rect->left && !rect->top && !rect->bottom ) + { + *rect = obj_def->v.container->xi_rct; + xi_fu_to_pu_font( font, ( XinPoint * ) rect, 2 ); + } +} + +/*--------------------------------------------------------------------------*/ +/* get_column_def_rect */ +/*--------------------------------------------------------------------------*/ +static void +get_column_def_rect( XinFont * font, XI_OBJ_DEF * obj_def, + XinRect * rect ) +{ + XI_OBJ_DEF *list; + XI_OBJ_DEF *itf; + + /* left and height is undefined without list context */ + rect->top = rect->bottom = 0; + rect->left = 0; + if ( obj_def->v.column->pixel_width ) + rect->right = obj_def->v.column->pixel_width; + else + { + rect->right = obj_def->v.column->width; + list = obj_def->parent; + if ( list == NULL ) + itf = NULL; + else + itf = list->parent; + + if ( xi_def_get_xil_pref( itf ) ) + { + if ( font ) + rect->right *= xi_get_fu_width_font( font ); + else + rect->right *= xi_get_fu_width( NULL ); + } + else + xi_fu_to_pu_font( font, ( XinPoint * ) rect, 2 ); + + } +} + +/*--------------------------------------------------------------------------*/ +/* get_interface_def_rect */ +/*--------------------------------------------------------------------------*/ +static void +get_interface_def_rect( XinFont * font, XI_OBJ_DEF * obj_def, + XinRect * rect ) +{ + BOOLEAN first_rect = TRUE; + XI_OBJ_DEF **defp; + int i, + n; + + MEMCLEAR( *rect ); + defp = obj_def->children; + n = obj_def->nbr_children; + for ( i = 0; i < n; defp++, i++ ) + { + if ( first_rect ) + { + if ( xi_get_def_rect( *defp, rect ) != NULL ) + first_rect = FALSE; + } + else + { + XinRect rct; + + if ( xi_get_def_rect( *defp, &rct ) != NULL ) + XinRectEnclose( rect, &rct, rect ); + } + } + if ( obj_def->type == XIT_ITF ) + { + int fu_width, + fu_height, + ws_right, + ws_bottom; + int ws_right_pix, + ws_bottom_pix; + + rect->left = 0; + rect->top = 0; + if ( !xi_def_get_xil_pref( obj_def ) ) + { + if ( font ) + { + fu_width = xi_get_fu_width_font( font ); + fu_height = xi_get_fu_height_font( font ); + } + else + { + fu_width = xi_get_fu_width( NULL ); + fu_height = xi_get_fu_height( NULL ); + } + ws_right = ( int ) xi_get_pref( XI_PREF_ITF_WS_RIGHT ); + ws_bottom = ( int ) xi_get_pref( XI_PREF_ITF_WS_BOTTOM ); + if ( obj_def->v.itf->use_whitespace ) + { + ws_right = obj_def->v.itf->whitespace_right; + ws_bottom = obj_def->v.itf->whitespace_bottom; + } + ws_right_pix = fu_width * ws_right / XI_FU_MULTIPLE; + ws_bottom_pix = fu_height * ws_bottom / XI_FU_MULTIPLE; + rect->bottom += ws_bottom_pix; + rect->right += ws_right_pix; + } + } +} + +/*--------------------------------------------------------------------------*/ +/* get_field_def_rect */ +/*--------------------------------------------------------------------------*/ +static void +get_field_def_rect( XinFont * font, XI_OBJ_DEF * obj_def, + XinRect * rect ) +{ + XI_FIELD_DEF *flddef = obj_def->v.field; + XinFont *parent_font = xi_def_get_font( obj_def->parent ); + + + if ( flddef->xi_rct.top || flddef->xi_rct.left || + flddef->xi_rct.bottom || flddef->xi_rct.right ) + { + *rect = flddef->xi_rct; + xi_fu_to_pu_font( parent_font, ( XinPoint * ) rect, 2 ); + } + else + { + if ( flddef->pixel_origin.v || flddef->pixel_origin.h ) + { + rect->top = flddef->pixel_origin.v; + rect->left = flddef->pixel_origin.h; + } + else + { + rect->top = flddef->pnt.v; + rect->left = flddef->pnt.h; + xi_fu_to_pu_font( parent_font, ( XinPoint * ) rect, 1 ); + } + { + XinPoint pnt; + + if ( flddef->pixel_width ) + pnt.h = 2 * XI_FU_MULTIPLE; + else + pnt.h = flddef->field_width; + pnt.v = XI_FU_MULTIPLE; + xi_fu_to_pu_font( font, &pnt, 1 ); + rect->bottom = rect->top + pnt.v; + if ( flddef->pixel_width ) + rect->right = rect->left + flddef->pixel_width + pnt.h; + else + /* add 4 for the 3d rect */ + rect->right = rect->left + pnt.h + 4; + } + } + XinFontDestroy( parent_font ); + if ( flddef->button ) + { + XinRect r; + int fu_width, + fu_height, + btn_dim_x, + btn_dim_x2, + btn_space; + + r.top = 0; + r.left = 0; + r.bottom = 8; + r.right = 8; + xi_fu_to_pu_font( font, ( XinPoint * ) & r, 2 ); + fu_width = r.right; + fu_height = r.bottom; + btn_dim_x = ( fu_height * XI_FU_MULTIPLE ) / fu_width; +#if XIWS != XIWS_WM + /* make buttons 70% wide as high */ + btn_dim_x = ( int ) ( ( long ) btn_dim_x * 83L / 100L ); +#endif + btn_space = btn_dim_x / 6; + /* btn_dim_x2 is the button width + space, rounded up to */ + /* the next even form unit */ + btn_dim_x2 = btn_dim_x + btn_space; + btn_dim_x2 = ( ( btn_dim_x2 + XI_FU_MULTIPLE ) / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + btn_dim_x = ( int ) ( ( ( long ) btn_dim_x * fu_width ) / XI_FU_MULTIPLE ); + btn_dim_x2 = ( int ) ( ( ( long ) btn_dim_x2 * fu_width ) / XI_FU_MULTIPLE ); + if ( flddef->button_on_left ) + { + rect->right += btn_dim_x; + if ( flddef->pixel_button_distance ) + rect->right += flddef->pixel_button_distance; + else + rect->right += ( btn_dim_x2 - btn_dim_x ); + } + else + { + rect->right += btn_dim_x; + if ( flddef->pixel_button_distance ) + rect->right += flddef->pixel_button_distance; + else + { + rect->right += ( btn_dim_x2 - btn_dim_x ); + /* convert to form units */ + rect->right = ( int ) ( ( ( long ) rect->right * XI_FU_MULTIPLE ) / fu_width ); + /* round up to nearest FU multiple */ + rect->right = ( ( rect->right + XI_FU_MULTIPLE ) / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + /* convert to pixels */ + rect->right = ( int ) ( ( ( long ) rect->right * fu_width ) / XI_FU_MULTIPLE ); + } + } + } +} + +/*--------------------------------------------------------------------------*/ +/* get_list_def_rect */ +/*--------------------------------------------------------------------------*/ +static void +get_list_def_rect( XinFont * font, XI_OBJ_DEF * obj_def, + XinRect * rect ) +{ + XI_LIST_DEF *list_def; + int list_xborder, + list_col_div, + width, + list_bottom; + int col_offset; + XinFont *parent_font = xi_def_get_font( obj_def->parent ); + + list_def = obj_def->v.list; + lm_get_metrics( obj_def, &list_xborder, &list_col_div, &list_bottom ); + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + if ( xi_def_get_xil_pref( obj_def->parent ) ) + { + rect->top = list_def->xi_pnt.v; + rect->left = list_def->xi_pnt.h; + width = list_def->width; + } + else + { + if ( list_def->pixel_origin.h || list_def->pixel_origin.v ) + { + rect->top = list_def->pixel_origin.h; + rect->left = list_def->pixel_origin.v; + } + else + { + rect->top = list_def->xi_pnt.v; + rect->left = list_def->xi_pnt.h; + xi_fu_to_pu_font( parent_font, ( XinPoint * ) rect, 1 ); + } + width = list_def->pixel_width; + if ( !width ) + { + XinPoint p; + + p.h = list_def->width; + p.v = 0; + xi_fu_to_pu_font( font, &p, 1 ); + width = p.h; + } + } + XinFontDestroy( parent_font ); + rect->bottom = 0; + if ( width ) + rect->right = rect->left + width + 2 * BORDER_WIDTH; + else + { + XI_OBJ_DEF **defp; + int i, + n; + + defp = obj_def->children; + n = obj_def->nbr_children; + rect->right = rect->left; + for ( i = 0; i < n; defp++, i++ ) + { + XinRect rct; + + xi_get_def_rect( *defp, &rct ); + rect->right += rct.right; + if ( i ) + rect->right += list_col_div; + else + rect->right += 2 * col_offset; + } + rect->right += BORDER_WIDTH * 2; + } + rect->bottom = list_bottom; + if ( list_def->scroll_bar ) + rect->right = rect->right + ( int ) xi_get_pref( XI_PREF_SB_OFFSET ) + + ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth ) - 1; + if ( width ) + rect->bottom += ( int ) XinMetricGet( XinMetricHorizontalScrollBarHeight ) + 3; +} + +/*--------------------------------------------------------------------------*/ +/* xi_get_def_rect */ +/*--------------------------------------------------------------------------*/ + +XinRect * +xi_get_def_rect_internal( XI_OBJ_DEF * xi_obj_def, XinRect * rect, BOOLEAN r4_api ) +{ + XinFont *font = NULL; + + xi_init_internal( r4_api ); + font = xi_def_get_font( xi_obj_def ); + MEMCLEAR( *rect ); + switch ( xi_obj_def->type ) + { + case XIT_BTN: + get_button_def_rect( font, xi_obj_def, rect ); + break; + case XIT_CONTAINER: + get_container_def_rect( font, xi_obj_def, rect ); + break; + case XIT_COLUMN: + get_column_def_rect( font, xi_obj_def, rect ); + break; + case XIT_ITF: + case XIT_FORM: + get_interface_def_rect( font, xi_obj_def, rect ); + break; + case XIT_FIELD: + get_field_def_rect( font, xi_obj_def, rect ); + break; + case XIT_LIST: + get_list_def_rect( font, xi_obj_def, rect ); + break; + case XIT_TEXT: + *rect = xi_obj_def->v.text->pixel_rect; + if ( !rect->left && !rect->right && !rect->top && !rect->bottom ) + { + XinFontDestroy( font ); + font = xi_def_get_font( xi_obj_def->parent ); + *rect = xi_obj_def->v.text->xi_rct; + xi_fu_to_pu_font( font, ( XinPoint * ) rect, 2 ); + } + break; + case XIT_GROUP: + /* no bounding rect for these guys! */ + XinFontDestroy( font ); + return ( NULL ); + case XIT_RECT: + *rect = xi_obj_def->v.rect->xi_rct; + xi_fu_to_pu_font( font, ( XinPoint * ) rect, 2 ); + break; + case XIT_LINE: + { + XI_LINE_DEF *line; + + line = xi_obj_def->v.line; + rect->top = min( line->pnt1.v, line->pnt2.v ); + rect->bottom = max( line->pnt1.v, line->pnt2.v ); + rect->left = min( line->pnt1.h, line->pnt2.h ); + rect->right = max( line->pnt1.h, line->pnt2.h ); + xi_fu_to_pu_font( font, ( XinPoint * ) rect, 2 ); + break; + } + case XIT_CELL: + case XIT_ROW: + default: + XinError( 20019, XinSeverityFatal, 0L ); + } + XinFontDestroy( font ); + return ( rect ); +} + +/* --------------------------------------------------------------------------*/ +/* xi_button_set_default */ +/* --------------------------------------------------------------------------*/ +static void +invalidate_button_rect( XI_OBJ * xi_obj ) +{ + XinRect rect = xi_obj->v.btn->rct; + XinWindow win; + + if ( xi_obj->v.btn->type == XIBT_TABBTN ) + rect.bottom += 2; + win = xi_obj->itf->v.itf->xin_win; + xi_invalidate_rect( win, &rect ); +} + +BOOLEAN +xi_button_set_default( XI_OBJ * xi_obj, BOOLEAN set ) +{ + if ( xi_obj == NULL ) + return FALSE; + if ( set ) /* clear previous default button */ + { + if ( xi_obj->type != XIT_BTN ) + return FALSE; + if ( !xi_obj->v.btn->dflt ) + { + xi_button_set_default( xi_obj->itf, FALSE ); + xi_obj->v.btn->dflt = TRUE; + invalidate_button_rect( xi_obj ); + } + return TRUE; + } + switch ( xi_obj->type ) + { + case XIT_BTN: + if ( xi_obj->v.btn->dflt ) + { + xi_obj->v.btn->dflt = FALSE; + invalidate_button_rect( xi_obj ); + } + return TRUE; + case XIT_CONTAINER: + case XIT_ITF: + { + XI_OBJ **ptr; + int i; + int n; + + ptr = xi_obj->children; + n = xi_obj->nbr_children; + for ( i = 0; i < n; ptr++, i++ ) + xi_button_set_default( *ptr, FALSE ); + return TRUE; + } + default: + break; + } + return FALSE; +} diff --git a/src/xi01/xidbg.c b/src/xi01/xidbg.c new file mode 100644 index 000000000..eb5762f84 --- /dev/null +++ b/src/xi01/xidbg.c @@ -0,0 +1,478 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#define XI_R3_COMPAT +#include "xi.h" +#include "xiutils.h" + +#define UNDEFINED 1000 +#define BUFFERLEN 200 + +static char * +bool_to_str( BOOLEAN b ) +{ + if ( b ) + return "TRUE"; + else + return "FALSE"; +} + +void +xi_event_debug( char *tag, XI_EVENT * xiev, char *s, int len ) +{ + char *tmp; + char str[BUFFERLEN], + str2[BUFFERLEN]; + int i, + k; + int j; + XI_OBJ *xi_obj; + + static struct + { + int type; + char *desc; + } event_text[] = + { + { + XIE_CHAR_FIELD, "XIE_CHAR_FIELD " + }, + { + XIE_DBL_FIELD, "XIE_DBL_FIELD " + }, + { + XIE_CHG_FIELD, "XIE_CHG_FIELD " + }, + { + XIE_OFF_FIELD, "XIE_OFF_FIELD " + }, + { + XIE_ON_FIELD, "XIE_ON_FIELD " + }, + { + XIE_OFF_GROUP, "XIE_OFF_GROUP " + }, + { + XIE_ON_GROUP, "XIE_ON_GROUP " + }, + { + XIE_OFF_FORM, "XIE_OFF_FORM " + }, + { + XIE_ON_FORM, "XIE_ON_FORM " + }, + { + XIE_VIR_PAN, "XIE_VIR_PAN " + }, + { + XIE_XVT_EVENT, "XIE_XVT_EVENT " + }, + { + XIE_XVT_POST_EVENT, "XIE_XVT_POST_EVENT" + }, + { + XIE_XIN_EVENT, "XIE_XIN_EVENT " + }, + { + XIE_XIN_POST_EVENT, "XIE_XIN_POST_EVENT" + }, + { + XIE_INIT, "XIE_INIT " + }, + { + XIE_BUTTON, "XIE_BUTTON " + }, + { + XIE_CHAR_CELL, "XIE_CHAR_CELL " + }, + { + XIE_CLEANUP, "XIE_CLEANUP " + }, + { + XIE_CLOSE, "XIE_CLOSE " + }, + { + XIE_COMMAND, "XIE_COMMAND " + }, + { + XIE_DBL_CELL, "XIE_DBL_CELL " + }, + { + XIE_GET_FIRST, "XIE_GET_FIRST " + }, + { + XIE_GET_LAST, "XIE_GET_LAST " + }, + { + XIE_GET_NEXT, "XIE_GET_NEXT " + }, + { + XIE_GET_PERCENT, "XIE_GET_PERCENT " + }, + { + XIE_GET_PREV, "XIE_GET_PREV " + }, + { + XIE_CELL_REQUEST, "XIE_CELL_REQUEST" + }, + { + XIE_CHG_CELL, "XIE_CHG_CELL " + }, + { + XIE_OFF_CELL, "XIE_OFF_CELL " + }, + { + XIE_ON_CELL, "XIE_ON_CELL " + }, + { + XIE_OFF_ROW, "XIE_OFF_ROW " + }, + { + XIE_ON_ROW, "XIE_ON_ROW " + }, + { + XIE_OFF_COLUMN, "XIE_OFF_COLUMN " + }, + { + XIE_ON_COLUMN, "XIE_ON_COLUMN " + }, + { + XIE_OFF_LIST, "XIE_OFF_LIST " + }, + { + XIE_ON_LIST, "XIE_ON_LIST " + }, + { + XIE_REC_ALLOCATE, "XIE_REC_ALLOCATE" + }, + { + XIE_REC_FREE, "XIE_REC_FREE " + }, + { + XIE_ROW_SIZE, "XIE_ROW_SIZE " + }, + { + XIE_SELECT, "XIE_SELECT " + }, + { + XIE_UPDATE, "XIE_UPDATE " + }, + { + XIE_COL_DELETE, "XIE_COL_DELETE " + }, + { + XIE_COL_MOVE, "XIE_COL_MOVE " + }, + { + XIE_COL_SIZE, "XIE_COL_SIZE " + }, + { + XIE_POST_NAVIGATION, "XIE_POST_NAVIGATION" + }, + { + UNDEFINED, "Unknown XI Event" + } + }; + + static struct + { + XinEventType type; + char *desc; + } xin_event_text[] = + { + { + XinEventCreate, "XinEventCreate" + }, + { + XinEventDestroy, "XinEventDestroy" + }, + { + XinEventFocus, "XinEventFocus" + }, + { + XinEventResize, "XinEventResize" + }, + { + XinEventPaint, "XinEventPaint" + }, + { + XinEventCloseButton, "XinEventCloseButton" + }, + { + XinEventMouseDown, "XinEventMouseDown" + }, + { + XinEventMouseUp, "XinEventMouseUp" + }, + { + XinEventMouseMove, "XinEventMouseMove" + }, + { + XinEventMouseDouble, "XinEventMouseDouble" + }, + { + XinEventCharacter, "XinEventCharacter" + }, + { + XinEventVScroll, "XinEventVScroll" + }, + { + XinEventHScroll, "XinEventHScroll" + }, + { + XinEventMenuCommand, "XinEventMenuCommand" + }, + { + XinEventControl, "XinEventControl" + }, + { + XinEventTimer, "XinEventTimer" + }, + { + XinEventQuit, "XinEventQuit" + }, + { + XinEventHelp, "XinEventHelp" + }, + { + XinEventFont, "XinEventFont" + }, + { + (XinEventType)UNDEFINED, "Unknown Xin Event" + } + }; + + static struct + { + int type; + char *desc; + } object_type[] = + { + { + XIT_BTN, "XIT_BTN" + }, + { + XIT_CONTAINER, "XIT_CONTAINER" + }, + { + XIT_FORM, "XIT_FORM" + }, + { + XIT_FIELD, "XIT_FIELD" + }, + { + XIT_GROUP, "XIT_GROUP" + }, + { + XIT_LINE, "XIT_LINE" + }, + { + XIT_RECT, "XIT_RECT" + }, + { + XIT_TEXT, "XIT_TEXT" + }, + { + XIT_CELL, "XIT_CELL" + }, + { + XIT_COLUMN, "XIT_COLUMN" + }, + { + XIT_ITF, "XIT_ITF" + }, + { + XIT_LIST, "XIT_LIST" + }, + { + XIT_ROW, "XIT_ROW" + }, + { + UNDEFINED, "Unknown XI Object Type" + } + }; + + for ( i = 0; event_text[i].type != xiev->type && + event_text[i].type != UNDEFINED; ++i ) + ; + sprintf( str, "%s: %s", tag, event_text[i].desc ); + *str2 = '\0'; + switch ( xiev->type ) + { +#ifdef XI_USE_XVT + case XIE_XVT_EVENT: + case XIE_XVT_POST_EVENT: + sprintf( str2, " %s", XinXvtEventTextGet( &xiev->v.xvte ) ); + break; +#endif + case XIE_XIN_EVENT: + case XIE_XIN_POST_EVENT: + for ( j = 0; xin_event_text[j].type != xiev->v.xin_event.type && + xin_event_text[j].type != UNDEFINED; ++j ) + ; + sprintf( str2, " %s", xin_event_text[j].desc ); + break; + case XIE_COMMAND: + sprintf( str2, " tag %d, shift %s, control %s", xiev->v.cmd.tag, + bool_to_str( xiev->v.cmd.shift ), bool_to_str( xiev->v.cmd.control ) ); + break; + case XIE_INIT: + case XIE_BUTTON: + case XIE_CLOSE: + case XIE_DBL_CELL: + case XIE_DBL_FIELD: + case XIE_CHG_FIELD: + case XIE_OFF_FIELD: + case XIE_ON_FIELD: + case XIE_OFF_GROUP: + case XIE_ON_GROUP: + case XIE_OFF_FORM: + case XIE_ON_FORM: + case XIE_CHG_CELL: + case XIE_OFF_CELL: + case XIE_ON_CELL: + case XIE_OFF_ROW: + case XIE_ON_ROW: + case XIE_OFF_COLUMN: + case XIE_ON_COLUMN: + case XIE_OFF_LIST: + case XIE_ON_LIST: + case XIE_CLEANUP: + xi_obj = xiev->v.xi_obj; + for ( k = 0; object_type[k].type != xi_obj->type && + object_type[k].type != UNDEFINED; ++k ) + ; + switch ( xi_obj->type ) + { + case XIT_CELL: + sprintf( str2, " cid %3d, type %s r %d c %d v %d", + xi_obj->cid, object_type[k].desc, xi_obj->v.cell.row, + xi_obj->v.cell.column, !xi_obj->v.cell.is_vert_scrolled ); + break; + case XIT_ROW: + sprintf( str2, " cid %3d, type %s r %d", xi_obj->cid, + object_type[k].desc, xi_obj->v.row ); + break; + default: + sprintf( str2, " cid %3d, type %s", xi_obj->cid, + object_type[k].desc ); + break; + } + break; + case XIE_CHAR_CELL: + case XIE_CHAR_FIELD: + { + char char_str[20]; + int ch; + + ch = xiev->v.chr.ch; + switch ( ch ) + { + case XI_KEY_CLEAR: + strcpy( char_str, "XI_KEY_CLEAR" ); + break; + case XI_KEY_DEL: + strcpy( char_str, "XI_KEY_DEL" ); + break; + case '\b': + strcpy( char_str, "BS" ); + break; + default: + char_str[0] = ( char ) ch; + char_str[1] = '\0'; + break; + } + xi_obj = xiev->v.chr.xi_obj; + for ( k = 0; object_type[k].type != xi_obj->type && + object_type[k].type != UNDEFINED; ++k ) + ; + switch ( xi_obj->type ) + { + case XIT_CELL: + sprintf( str2, + " cid %3d type %s r %d c %d ch %s shft %d ctrl %d alt %d", + xi_obj->cid, object_type[k].desc, xi_obj->v.cell.row, + xi_obj->v.cell.column, char_str, xiev->v.chr.shift, + xiev->v.chr.control, xiev->v.chr.alt ); + break; + case XIT_FIELD: + sprintf( str2, " cid %3d type %s ch %s shft %d ctrl %d alt %d", xi_obj->cid, + object_type[k].desc, char_str, xiev->v.chr.shift, + xiev->v.chr.control, xiev->v.chr.alt ); + break; + default: + break; + } + break; + } + case XIE_GET_FIRST: + case XIE_GET_LAST: + sprintf( str2, " data_rec %08.8lx", ( long ) xiev->v.rec_request.data_rec ); + break; + case XIE_GET_NEXT: + case XIE_GET_PREV: + sprintf( str2, " spec_rec %08.8lx, data_rec %08.8lx", + ( long ) xiev->v.rec_request.spec_rec, ( long ) xiev->v.rec_request.data_rec ); + break; + case XIE_CELL_REQUEST: + sprintf( str2, " c %2d, rec %08.8lx, len %3d", + ( int ) xiev->v.cell_request.col_nbr, ( long ) xiev->v.cell_request.rec, + xiev->v.cell_request.len ); + break; + case XIE_GET_PERCENT: + sprintf( str2, " list->cid %d, record %08.8lx", + xiev->v.get_percent.list->cid, + ( long ) xiev->v.get_percent.record ); + break; + case XIE_SELECT: + sprintf( str2, " row %d, selected %d, dbl_click %d shift %d control %d column %d", + xiev->v.select.xi_obj->v.row, xiev->v.select.selected, + xiev->v.select.dbl_click, xiev->v.select.shift, xiev->v.select.control, xiev->v.select.column ); + break; + case XIE_REC_ALLOCATE: + sprintf( str2, " list cid %d", xiev->v.rec_allocate.list->cid ); + break; + case XIE_REC_FREE: + sprintf( str2, " list cid %d, record %08.8lx", xiev->v.rec_free.list->cid, xiev->v.rec_free.record ); + break; + case XIE_ROW_SIZE: + sprintf( str2, " row %d, new_size %d", xiev->v.row_size.xi_obj->v.row, xiev->v.row_size.new_row_height ); + break; + case XIE_VIR_PAN: + sprintf( str2, " delta_x %d, delta_y %d, before_pan %d", + xiev->v.vir_pan.delta_x, xiev->v.vir_pan.delta_y, + xiev->v.vir_pan.before_pan ); + break; + case XIE_COL_DELETE: + sprintf( str2, " list cid %d, col_nbr %d", + xiev->v.column.list->cid, xiev->v.column.col_nbr ); + break; + case XIE_COL_MOVE: + sprintf( str2, " list cid %d, col_nbr %d, new_col_nbr %d", + xiev->v.column.list->cid, xiev->v.column.col_nbr, + xiev->v.column.new_col_nbr ); + break; + case XIE_COL_SIZE: + sprintf( str2, " list cid %d, col_nbr %d, new_col_width %d, new_col_pixel_width %d", + xiev->v.column.list->cid, xiev->v.column.col_nbr, + xiev->v.column.new_col_width, xiev->v.column.new_col_pixel_width ); + break; + default: + break; + } + tmp = ( char * ) xi_tree_malloc( strlen( str ) + strlen( str2 ) + 2, NULL ); + strcpy( tmp, str ); + strcat( tmp, str2 ); + if ( ( int ) strlen( tmp ) >= len ) + tmp[len] = '\0'; + strcpy( s, tmp ); + xi_tree_free( tmp ); +} diff --git a/src/xi01/xidisply.h b/src/xi01/xidisply.h new file mode 100644 index 000000000..3739ff365 --- /dev/null +++ b/src/xi01/xidisply.h @@ -0,0 +1,34 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define C_UL 218 /* upper left */ +#define C_UR 191 /* upper right */ +#define C_LL 192 /* lower left */ +#define C_LR 217 /* lower right */ +#define C_XD 194 /* T-intersection down */ +#define C_XU 193 /* T-intersection up */ +#define C_XR 195 /* T-intersection right */ +#define C_XL 180 /* T-intersection left */ +#define C_XX 197 /* 4-way intersection */ +#define C_H 196 /* horizontal line */ +#define C_V 179 /* vertical line */ +#define C_ULD 201 /* next group same as above, but double */ +#define C_URD 187 +#define C_LLD 200 +#define C_LRD 188 +#define C_XDD 203 +#define C_XUD 202 +#define C_XRD 204 +#define C_XLD 185 +#define C_XXD 206 +#define C_HD 205 +#define C_VD 186 +#define C_HATCH 176 /* hatching */ +#define C_SPACE 255 diff --git a/src/xi01/xierr.c b/src/xi01/xierr.c new file mode 100644 index 000000000..ac20422fa --- /dev/null +++ b/src/xi01/xierr.c @@ -0,0 +1,316 @@ + + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#include "xi.h" + +static struct s_error_entry +{ + int errcode; + char *text; +} error_table[] = + +{ + { + 1000, "Error: Problem 1000" + }, + { + 1001, "Warning: Problem 1001" + }, + { + 1002, "Error: XI_TEXT internal error" + }, + { + 20001, "XI: internal object deletion error" + }, + { + 20002, "Internal XI error" + }, + { + 20003, "Internal error" + }, + { + 20004, "Internal XI error" + }, + { + 20005, "Internal error" + }, + { + 20006, "Attempting to move to disabled or invisible object" + }, + { + 20007, "Attempting to move to disabled or invisible object" + }, + { + 20008, "XI: unknown STX callback" + }, + { + 20009, "XI: unknown LM callback" + }, + { + 20010, "Non-column object sent to xi_column_set_pixel_width" + }, + { + 20011, "Can't create empty container" + }, + { + 20012, "Containers can only contain buttons" + }, + { + 20013, "Can't mix button types in a container" + }, + { + 20014, "Not enough room in container for buttons" + }, + { + 20015, "Internal XI error" + }, + { + 20016, "xi_create: Invalid XI_OBJ_TYPE" + }, + { + 20017, "Invalid XI object passed to xi_delete" + }, + { + 20018, "Invalid object passed to xi_get_attrib" + }, + { + 20019, "xi_get_def_rect: Invalid XI_OBJ_TYPE in tree" + }, + { + 20020, "Non-list object passed to xi_get_list_info" + }, + { + 20021, "xi_get_rect: Invalid XI_OBJ_TYPE in tree" + }, + { + 20022, "Invalid object passed to xi_get_sel" + }, + { + 20023, "xi_get_text not implemented for XIT_ROW" + }, + { + 20024, "Invalidate object passed to xi_scroll_rec" + }, + { + 20025, "Invalidate object passed to xi_delete_row" + }, + { + 20026, "Invalidate object passed to xi_insert_row" + }, + { + 20027, "Invalid object passed to xi_set_attrib" + }, + { + 20028, "Invalid object passed to xi_set_sel" + }, + { + 20029, "xi_set_text not implemented for XIT_ROW" + }, + { + 20030, "Internal focus error" + }, + { + 20031, "Non-list object sent to xi_set_fixed_columns" + }, + { + 20032, "button height exceeds container height" + }, + { + 20033, "button width exceeds container width" + }, + { + 20034, "height must be at least 8 form units" + }, + { + 20035, "Buttons won't fit in container" + }, + { + 20036, "xi_container_reorient() passed wrong object type" + }, + { + 20037, "Invalidate object passed to xi_scroll_internal" + }, + { + 20038, "Non-list object sent to xi_get_fixed_columns" + }, + { + 20039, "Non-interface object sent to xi_itf_closing_is" + }, + { + 20050, "xi_create: Rectangles cannot have children" + }, + { + 20051, "xi_create: Lines cannot have children" + }, + { + 20052, "xi_create: Buttons cannot have children" + }, + { + 20053, "xi_create: Fields cannot have children" + }, + { + 20055, "xi_create: Static text controls cannot have children" + }, + { + 20056, "xi_create: Columns cannot have children" + }, + { + 20088, "xi_set_icon: Invalid object" + }, + { + 20089, "Too many radio buttons in a container" + }, + { + 20090, "create_window returned NULL" + }, + { + 20091, "Window information corrupt" + }, + { + 20092, "Window information corrupt" + }, + { + 20094, "Window information corrupt" + }, + { + 20095, "XinAppSystemSetupInit was not provided." + }, + { + 20101, "Invalid interface passed to xi_add_form_def" + }, + { + 20102, "Invalid interface passed to xi_add_list_def" + }, + { + 20103, "Invalid list passed to xi_add_column_def" + }, + { + 20104, "Invalid form passed to xi_add_field_def" + }, + { + 20105, "Invalid interface passed to xi_add_container_def" + }, + { + 20106, "Invalid parent passed to xi_add_button_def" + }, + { + 20107, "Invalid interface passed to xi_add_text_def" + }, + { + 20108, "Invalid interface passed to xi_add_line_def" + }, + { + 20109, "Groups must have at least one member" + }, + { + 20110, "Invalid interface passed to xi_add_group_def" + }, + { + 20111, "Invalid interface passed to xi_add_rect_def" + }, + { + 20112, "Invalid field buffer size" + }, + { + 20201, "Out of memory" + }, + { + 20907, "lm_get_attrib: Invalid LM part" + }, + { + 20908, "Attempting to get text from an invalid cell" + }, + { + 20915, "Invalid column number passed to lm_delete_column" + }, + { + 20917, "lm_set_buf_size: Invalid LM part" + }, + { + 20918, "lm_cell_request: Invalid LM part" + }, + { + 20919, "xi_insert_row called with get_all_records set to TRUE" + }, + { + 20920, "xi_delete_row called with get_all_records set to TRUE" + }, + { + 20921, "lm_focus_cell_set called when list does not have focus" + }, + { + 30101, "Internal focus error" + }, + { + 30201, "Internal TEXT error" + }, + { + 30202, "Internal TEXT error" + }, + { + 30203, "Internal error" + }, + { + 30205, "txt_caret called with disabled field" + }, + { + 30206, "Invalid TXT passed to txt_event" + }, + { + 30207, "xi_get_obj: Invalid cid" + }, + { + 30208, "width or height required with grid" + }, + { + 30209, "lm_start_edit: Internal error, called with focus not poperly set" + }, + { + 0, "Unknown Error" + } +}; + +char * +XinErrorCodeLookup( int errcode ) +{ + struct s_error_entry *entry; + static char temp[30]; + + for ( entry = error_table; entry->errcode != 0 && entry->errcode != errcode; + entry++ ) + ; + if ( entry->errcode == 0 ) + { + sprintf( temp, "XIN Error %d", errcode ); + return temp; + } + return entry->text; +} + +BOOLEAN +XinErrorDefaultHandler( int errcode, XinSeverity severity, long app_data ) +{ + BOOLEAN terminate = FALSE; + + NOREF( app_data ); + if ( severity == XinSeverityFatal ) + { + terminate = TRUE; + XinDialogError( "%s", XinErrorCodeLookup( errcode ) ); + } + else + { + if ( XinDialogAsk( "Continue", "Terminate", NULL, "%s", + XinErrorCodeLookup( errcode ) ) == XinResponse2 ) + terminate = TRUE; + } + return terminate; +} diff --git a/src/xi01/xiextend.h b/src/xi01/xiextend.h new file mode 100644 index 000000000..0d539e8c6 --- /dev/null +++ b/src/xi01/xiextend.h @@ -0,0 +1,65 @@ +/******************************************************************************* +* Copyright 1991-1995 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. * +*******************************************************************************/ + +#ifdef WSWIN +#define NOCOMM +#define NOMINMAX +#define NOGDICAPMASKS +#define NOVIRTUALKEYCODES +#define NOWINMESSAGES +#define NOWINSTYLES +#define NOSYSMETRICS +#define NOMENUS +#define NOICONS +#define NOKEYSTATES +#define NOSYSCOMMANDS +#define NORASTEROPS +#define NOSHOWWINDOW +#define OEMRESOURCE +#define NOATOM +#define NOCLIPBOARD +#define NOCOLOR +#define NOCTLMGR +#define NODRAWTEXT +#define NOGDI +#define NOKERNEL +/* #define NOUSER */ +#define NOMB +#define NOMEMMGR +#define NOMETAFILE +#define NOMINMAX +#define NOMSG +#define NOOPENFILE +#define NOSCROLL +#define NOSOUND +#define NOTEXTMETRIC +#define NOWH +#define NOWINOFFSETS +#define NOCOMM +#define NOKANJI +#define NOHELP +#define NOPROFILER +#define NODEFERWINDOWPOS +#include +#define INTERNAL +#endif + +#ifdef OSOS2 +#define INCL_DOS +#define INCL_WIN +#define INCL_GPI +#define COLOR pm_COLOR +#define UINT pm_UINT +#define ULONG pm_ULONG +#include +#undef COLOR +#undef UINT +#undef ULONG +#define INTERNAL +#endif + + diff --git a/src/xi01/xiheap.c b/src/xi01/xiheap.c new file mode 100644 index 000000000..a165760ba --- /dev/null +++ b/src/xi01/xiheap.c @@ -0,0 +1,59 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL + +#include "xi.h" +#include "xiheap.h" + +#ifdef DEBUG +int nbr_malloc, +nbr_free; + +#endif + +void * +heap_malloc( size_t size ) +{ + void *p; + +#ifdef DEBUG + nbr_malloc++; +#endif + p = XinMemoryAlloc( size ); + if ( p != NULL ) + memset( ( char * ) p, '\0', ( size_t ) size ); + return ( p ); +} + +void +heap_free( void *p ) +{ +#ifdef DEBUG + nbr_free++; +#endif + XinMemoryFree( ( char * ) p ); +} + +void * +heap_realloc( void *p, size_t size ) +{ + return ( XinMemoryRealloc( ( char * ) p, size ) ); +} + +void +heap_dbg( char *title ) +{ +#ifdef DEBUG + XinDebugPrintf( "heap check (%Fs): malloc's=%u, free's=%u", title, nbr_malloc, nbr_free ); +#else + NOREF( title ); +#endif +} diff --git a/src/xi01/xiheap.h b/src/xi01/xiheap.h new file mode 100644 index 000000000..d9814e109 --- /dev/null +++ b/src/xi01/xiheap.h @@ -0,0 +1,49 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +/****************************************************************** +Heap module +******************************************************************/ +void *heap_malloc( size_t size ); +void heap_free( void *p ); +void *heap_realloc( void *p, size_t size ); +void heap_dbg( char *title ); + +#define MAX_NODE_SIZE 16000 +#define HEAP_SIZE 32000 + +#define NODE_SET_MAGIC(node) (node->size = 0xFFFF) +#define NODE_IS_MAGIC(node) (node->size == 0xFFFF) + +#define NODE_MARK_ALLOCATED(node) (node->size |= 0x8000) +#define NODE_MARK_FREE(node) (node->size &= 0x7FFF) +#define NODE_IS_FREE(node) ( (node->size & 0x8000) == 0 ) + +#define NODE_SET_SIZE(node, n) (node->size = (node->size & 0x8000) | (n)) +#define NODE_GET_SIZE(node) (node->size & 0x7FFF) + +#define PTR_IS_GLOBAL(p) ((PTR_LONG(p) & 0xFFFF) == 0) +#define NEXT_NODE(node) ( (NODE *)((char *)node + sizeof(NODE) + NODE_GET_SIZE(node))) + +#define PTR_TO_NODE(p) ((NODE *)(p) - 1) +#define NODE_TO_PTR(node) ((char *)(node + 1)) + +typedef struct _s_node +{ + unsigned short size; +} NODE; + +typedef struct _s_enode +{ + unsigned short size; /* equal to NODE_MAGIC */ + struct _s_node *next; /* pointer to next heap */ +} E_NODE; + +#define ALIGNMENT (sizeof(NODE)) diff --git a/src/xi01/xil.h b/src/xi01/xil.h new file mode 100644 index 000000000..bb8b13825 --- /dev/null +++ b/src/xi01/xil.h @@ -0,0 +1,48 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#ifndef INCL_XIL +#define INCL_XIL + +#include "xi.h" + +#include "xvtcm.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct + { + XVTCM_CONTROL_INFO ci; + XI_OBJ *itf; + XI_EVENT *xiev; + } XIL_DATA; + + WINDOW XVT_CALLCONV1 xil_create XVT_CC_ARGS( ( int cid, int left, int top, + int right, int bottom, int prop_count, + char **prop_list, WINDOW parent_win, + int parent_rid, long parent_flags, + char *parent_class ) ); + XI_OBJ_DEF *XVT_CALLCONV1 xil_parse XVT_CC_ARGS( ( int cid, int prop_count, + char **prop_list ) ); + + WINDOW XVT_CALLCONV1 xis_create XVT_CC_ARGS( ( int cid, int left, int top, + int right, int bottom, int prop_count, + char **prop_list, WINDOW parent_win, + int parent_rid, long parent_flags, + char *parent_class ) ); + +#ifdef __cplusplus +} + +// End of extern "C" +#endif +#endif diff --git a/src/xi01/xilm.c b/src/xi01/xilm.c new file mode 100644 index 000000000..6bc80fd06 --- /dev/null +++ b/src/xi01/xilm.c @@ -0,0 +1,1622 @@ + + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#include "xi.h" +#include "xitext.h" +#include "xilm.h" +#include "xilmst.h" +#include "xiutils.h" +#include "xidisply.h" + +/*------------------------------------------------------------------------- +Metrics Documentation +lmp->rct.top and lmp->rct.bottom are the top and bottom of the list, excluding the + horizontal scroll bar. +lmp->rct.left is the physical left position of the list +lmp->rct.right is the position of the physical right position of the list. However, if the + list is a horizontal scrolling list, then lmp->rct.right will be beyond lmp->width. + It is useful for drawing using the virtual functions, but it is necessary to subtract + lmp->rct.left before calling the drawing functions, because the drawing functions will + add lmp->rct.left to the h values before drawing. +-------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------- +ROWS: REALIZED, and ALLOCATED-USED, and ALLOCATED-NOT USED. + +In the realized rows array, there are three types of rows. + +First, there are rows that are not being used at all. These are the rows +after lmp->nbr_realized_rows. The record handles for these rows are 0L. + +Second, there are rows that are allocated, and used. These are the rows +after 0, and before lmp->nbr_realized_rows. +The record handles for these rows are not 0L. + +Third, there are rows that are allocated, and not used. These are the rows +after 0, and less than lmp->nbr_realized_rows. +The record handles for these rows are not 0L. If one of these rows is requested +to be allocated, and the handle is not 0L, then then allocation event is not +done. If one of these rows is requested to be freed, and the handle is 0L, +then the free event is not done. +-------------------------------------------------------------------------*/ + +/* Error codes: 20900 - 20918 */ + + +#define LM_REDRAW_ATR (LM_ATR_VISIBLE | LM_ATR_ENABLED) + +#define LM_REQUESTING_CELL(lm, row, col) (LMP(lm)->in_cell_request && LMP(lm)->cell_request_row == (row) && LMP(lm)->cell_request_col == (col)) + +#define BUFLEN 256 + + + + +/*------------------------------------------------------------------------- +function: calc_last_vis +lmp: current lmp +process: calculates the last fully visible column in the list +-------------------------------------------------------------------------*/ +void +lm_calc_last_vis( LM_DATA * lmp ) +{ + LM_COLUMN_DATA *column_data; + int l1; + + if ( !lmp->pixel_width ) + lmp->last_vis = lmp->nbr_columns - 1; + else + { + lmp->last_vis = lmp->first_vis; + for ( l1 = lmp->first_vis + 1; l1 < lmp->nbr_columns; ++l1 ) + { + column_data = lmp->lm_column_data[l1]; + if ( ( column_data->x_pix_pos - lmp->delta_x + column_data->pix_width ) + >= lmp->pixel_width ) + { + lmp->last_vis = l1 - 1; + return; + } + lmp->last_vis = l1; + } + if ( l1 == lmp->nbr_columns ) + lmp->last_vis = l1 - 1; + } +} + +/*------------------------------------------------------------------------- +function: lm_get_col_spacing +returns: column spacing +-------------------------------------------------------------------------*/ +int +lm_get_col_spacing( void ) +{ + return ( 2 * ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ) + RULE_WIDTH_V ); +} + +/*------------------------------------------------------------------------- +function: lm_get_left_most_far_right_column +lmp: current lmp +nbr_columns: column, from which we will count back +notes: This function is also used when the users presses page up on the + horizontal scroll bar, to determine the new left most column. + Get the column number for the column that would be visible if the + list is scrolled entirely over to the right. This is necessary + to compute the position of the horizontal thumb, and other reasons. +-------------------------------------------------------------------------*/ +int +lm_get_left_most_far_right_col( LM_DATA * lmp, int nbr_columns ) +{ + int width, + i; + +#if XIWS == XIWS_WM + width = lmp->pixel_width; +#else + width = lmp->pixel_width + ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ) + + RULE_WIDTH_V; +#endif + for ( i = 0; i < min( lmp->fixed_columns, lmp->nbr_columns ); ++i ) + width -= lmp->lm_column_data[i]->pix_width + lm_get_col_spacing( ); + for ( i = nbr_columns - 1; i >= lmp->fixed_columns; --i ) + { + width -= lmp->lm_column_data[i]->pix_width + lm_get_col_spacing( ); + if ( width <= 0 ) + break; + } + return ( i + 1 ); +} + + +/*------------------------------------------------------------------------- +function: lm_get_cell_rect +rctp: pointer to rectangle to be filled in +lm: current lm +row: relevant row +col: relevant column +inner: if TRUE, get the inner rectangle of the cell, else get the outer + rectangle of the cell +physical_rct: if TRUE, get the physical rectangle, else get the virtual + rectangle +notes: This function is called before starting the text edit object for the cell. +returns: rctp +-------------------------------------------------------------------------*/ +XinRect * +lm_get_cell_rect( XinRect * rctp, LM lm, int row, int col, BOOLEAN inner, BOOLEAN physical_rct ) +{ + LM_COLUMN_DATA *temp_lmcd; + int col_offset; + LM_DATA *lmp = LMP( lm ); + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + temp_lmcd = lmp->lm_column_data[col]; + + rctp->top = lmp->pix_offsets[row]; +#if XIWS != XIWS_WM + rctp->bottom = rctp->top + lmp->pix_heights[row] - RULE_WIDTH_V; +#else + rctp->bottom = rctp->top + lmp->pix_heights[row]; +#endif + + rctp->left = temp_lmcd->x_pix_pos; + rctp->right = rctp->left + temp_lmcd->pix_width + 2 * + ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + + if ( inner ) + { + rctp->left += col_offset; + rctp->right -= col_offset; +#if XIWS != XIWS_WM + rctp->top += RULE_Y_OFFSET_TOP; + rctp->bottom -= RULE_Y_OFFSET_BOTTOM; +#endif + } + if ( physical_rct ) + { + rctp->left += lmp->rct.left; + rctp->right += lmp->rct.left; + + if ( rctp->left >= lmp->vir_left ) + { + rctp->left -= lmp->delta_x; + rctp->right -= lmp->delta_x; + } + + rctp->top = rctp->top + lmp->rrr_offset + lmp->mlr.top; + rctp->bottom = rctp->bottom + lmp->rrr_offset + lmp->mlr.top; + } + return ( rctp ); +} + + +/*------------------------------------------------------------------------- +function: get_row_rect +rctp: pointer to rectangle to be filled in +lm: current lm +row: relevant row +returns: rctp +-------------------------------------------------------------------------*/ +XinRect * +lm_get_row_rect( XinRect * rctp, LM lm, int row ) +{ + LM_DATA *lmp = LMP( lm ); + + rctp->top = lmp->pix_offsets[row]; + rctp->bottom = rctp->top + lmp->pix_heights[row]; + + rctp->left = lmp->rct.left + BORDER_WIDTH; +#if XIWS != XIWS_WM + rctp->right = lmp->rct.right - BORDER_WIDTH; +#else + rctp->right = lmp->rct.right; +#endif + if ( lmp->pixel_width ) + rctp->right = rctp->left + lmp->pixel_width; + + return ( rctp ); +} + + +/*------------------------------------------------------------------------- +function: lm_adj_h +lmp: current lmp +h: pointer to horizontal coord to convert +returns: TRUE if position is visible +-------------------------------------------------------------------------*/ +BOOLEAN +lm_adj_h( LM_DATA * lmp, short *h ) +{ + if ( *h >= lmp->vir_left ) + { + XinRect r; + + *h -= lmp->delta_x; + if ( *h < lmp->vir_left ) + return FALSE; + r = lmp->rct; + if ( lmp->pixel_width ) + r.right = r.left + lmp->pixel_width + 2 * BORDER_WIDTH; + return ( *h <= r.right ); + } + return TRUE; +} + +/*------------------------------------------------------------------------- +function: lm_get_list_rct +lmp: current lmp +r: pointer to rectangle to be filled in +returns: r +-------------------------------------------------------------------------*/ +XinRect * +lm_get_list_rct( LM_DATA * lmp, XinRect * r ) +{ + *r = lmp->rct; + if ( lmp->pixel_width ) + r->right = r->left + lmp->pixel_width + 2 * BORDER_WIDTH; + return r; +} + +/*------------------------------------------------------------------------- +function: lm_set_fixed_columns +-------------------------------------------------------------------------*/ +void +lm_set_fixed_columns( LM lm, int new_fixed_count ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + int col_spacing, + i; + XinRect rct_to_invalidate, + rct; + + if ( new_fixed_count > lmp->nbr_columns ) + new_fixed_count = lmp->nbr_columns; + col_spacing = lm_get_col_spacing( ); + lmp->fixed_columns = new_fixed_count; + lmp->first_vis = lmp->fixed_columns; + lmp->delta_x = 0; + + /* calculate the left boundary of the virtual space for the list */ + lmp->vir_left = lmp->rct.left + BORDER_WIDTH; + for ( i = 0; i < min( lmp->nbr_columns, lmp->fixed_columns ); ++i ) + { + lmp->vir_left += lmp->lm_column_data[i]->pix_width; + lmp->vir_left += col_spacing; + } + lmp->list_obj->v.list->have_hsb_rct = FALSE; + lm_get_list_rct( lmp, &rct_to_invalidate ); + xi_invalidate_rect( lmp->win, &rct_to_invalidate ); + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + xi_get_hsb_rect( lmp->list_obj, &rct ); + xi_offset_rect( &rct, -lmp->list_obj->itf->v.itf->delta_x, + -lmp->list_obj->itf->v.itf->delta_y ); + XinWindowRectSet( lmp->list_obj->v.list->hsb_win, &rct ); +} + +/*------------------------------------------------------------------------- +function: lm_cleanup +lm: current lm +notes: Destroys all row data and fonts +-------------------------------------------------------------------------*/ +void +lm_cleanup( LM lm ) +{ + LM_DATA *lmp = LMP( lm ); + int col_nbr; + + for ( col_nbr = 0; col_nbr < lmp->nbr_columns; col_nbr++ ) + { + if ( lmp->lm_column_data[col_nbr]->font ) + XinFontDestroy( lmp->lm_column_data[col_nbr]->font ); + xi_bitmap_destroy( lmp->lm_column_data[col_nbr]->bitmap ); + } + + lm_remove_all_rows( lmp, TRUE ); +} + +/*------------------------------------------------------------------------- +function: lm_delete +lm: current lm +notes: do not call this function in response to XinEventDestroy. +-------------------------------------------------------------------------*/ +void +lm_delete( LM lm ) +{ + XinRect r; + LM_DATA *lmp = LMP( lm ); + int focus_row, + focus_column; + BOOLEAN v_scrolled; + + if ( lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ) ) + { + lm_focus_remove( lmp, focus_row, focus_column, v_scrolled ); + } + lm_cleanup( lm ); + lm_get_list_rct( lmp, &r ); + xi_invalidate_rect( lmp->win, &r ); + xi_tree_free( ( char * ) lm ); +} + +/*------------------------------------------------------------------------- +function: calc_x_pix_pos +lm: current lm +lcdata: column data pointer +position: position of column +-------------------------------------------------------------------------*/ +void +calc_x_pix_pos( LM lm, LM_COLUMN_DATA * lcdata, int position ) +{ + LM_DATA *lmp = LMP( lm ); + LM_COLUMN_DATA *lmcd; + + if ( position ) + lmcd = lmp->lm_column_data[position - 1]; + lcdata->x_pix_pos = ( !position ) ? BORDER_WIDTH : + lmcd->x_pix_pos + lmcd->pix_width + lm_get_col_spacing( ); +} + +/*------------------------------------------------------------------------- +function: lm_invalidate_rect +lmp: current lmp +rctp: rectangle to invalidate +adj_h: adjust the horizontal coords +-------------------------------------------------------------------------*/ +void +lm_invalidate_rect( LM_DATA * lmp, XinRect * rctp, BOOLEAN adj_h ) +{ + XinRect r; + + r = *rctp; + if ( adj_h ) + { + lm_adj_h( lmp, &r.left ); + lm_adj_h( lmp, &r.right ); + } + + lm_adj_v( lmp, r.top ); + lm_adj_v( lmp, r.bottom ); + + xi_invalidate_rect( lmp->win, &r ); +} + +/*------------------------------------------------------------------------- +function: lm_invalidate_rect2 +lmp: current lmp +rctp: rectangle to invalidate +adj_left: if TRUE, adjust left of rctp +-------------------------------------------------------------------------*/ +void +lm_invalidate_rect2( LM_DATA * lmp, XinRect * rctp, BOOLEAN adj_left ) +{ + XinRect r; + + r = *rctp; + if ( adj_left ) + lm_adj_h( lmp, &r.left ); + xi_invalidate_rect( lmp->win, &r ); +} + + +/*------------------------------------------------------------------------- +function: lm_get_fixed_columns +-------------------------------------------------------------------------*/ +int +lm_get_fixed_columns( LM lm ) +{ + return ( ( LM_DATA * ) lm )->fixed_columns; +} + + +void +lm_local_hscroll( LM lm, int nbr_columns ) +{ + LM_DATA *lmp; + XI_LIST_DATA *list_data; + XI_OBJ *other_list; + + lmp = ( LM_DATA * ) lm; + list_data = lmp->list_obj->v.list; + lm_hscroll( lm, nbr_columns, 0 ); + if ( list_data->horz_sync_list && + !list_data->scrolling_in_progress ) + { + list_data->scrolling_in_progress = TRUE; + other_list = xi_get_obj( lmp->itf_obj, + list_data->horz_sync_list ); + if ( other_list ) + lm_hscroll( other_list->v.list->lm, nbr_columns, 0 ); + list_data->scrolling_in_progress = FALSE; + } +} + +static void +lm_xi_text_set_color_and_attrib( LM_DATA * lmp, LM_COLUMN_DATA * lm_column_data, + LM_CELL_DATA * cell_data, int row ) +{ + unsigned long attrib, + cell_attrib; + + cell_data->xi_text->fore_color = lmp->enabled_color; + if ( lmp->row_colors[row] ) + cell_data->xi_text->fore_color = lmp->row_colors[row]; + if ( cell_data->color ) + cell_data->xi_text->fore_color = cell_data->color; + cell_data->xi_text->back_color = lmp->back_color; + if ( cell_data->back_color ) + cell_data->xi_text->back_color = cell_data->back_color; + cell_attrib = cell_data->attrib & + ( XI_ATR_HCENTER | XI_ATR_RJUST ); + attrib = lm_column_data->attrib; + if ( cell_attrib ) + { + attrib &= ~( XI_ATR_HCENTER | XI_ATR_RJUST ); + attrib |= cell_attrib; + } + xi_text_right_justify_set( cell_data->xi_text, ( BOOLEAN ) ( ( attrib & XI_ATR_RJUST ) != 0 ) ); +} + +void +lm_xi_text_construct( LM_DATA * lmp, int row, int column ) +{ + XinFont *font; + LM_COLUMN_DATA *lm_column_data; + int pix_spacing; + LM_CELL_DATA *cell_data; + XinRect rect; + + lm_column_data = lmp->lm_column_data[column]; + cell_data = &lmp->cell_data[row][column]; + pix_spacing = lm_column_data->pix_width - + ( cell_data->button ? lmp->pix_row_spacing : 0 ); + if ( cell_data->font ) + font = cell_data->font; + else if ( lmp->font ) + font = lmp->font; + else + font = xi_get_system_font( ); + cell_data->xi_text = + xi_text_construct( lmp->win, pix_spacing, font, lmp, lm_column_data->wrap_text, + XI_MULTILINE_SCROLLBAR_CID, FALSE ); + rect = lmp->mlr; + if ( lmp->pixel_width ) + rect.right = rect.left + lmp->pixel_width; + xi_text_clip_set( cell_data->xi_text, &rect ); + lm_xi_text_set_color_and_attrib( lmp, lm_column_data, cell_data, row ); + xi_text_parent_obj_set( cell_data->xi_text, lmp->list_obj ); + xi_text_scrollbar_set( cell_data->xi_text, lm_column_data->wrap_text_scrollbar ); + xi_text_read_only_set( cell_data->xi_text, ( lm_column_data->attrib & XI_ATR_READONLY ) != 0 ); + xi_text_password_set( cell_data->xi_text, ( lm_column_data->attrib & XI_ATR_PASSWORD ) != 0 ); + xi_text_cr_ok_set( cell_data->xi_text, lm_column_data->cr_ok ); + xi_text_var_len_text_set( cell_data->xi_text, lm_column_data->var_len_text ); + xi_text_pix_width_set( cell_data->xi_text, pix_spacing ); + xi_text_buffer_size_set( cell_data->xi_text, lm_column_data->text_size ); + xi_text_min_buffer_size_set( cell_data->xi_text, lm_column_data->text_size ); +} + +/*------------------------------------------------------------------------- +function: do_lm_cb_text +lm: current lm +row: row +col: column +-------------------------------------------------------------------------*/ +void +do_lm_cb_text( LM_DATA * lmp, int row, int col, BOOLEAN preserve_focus_text ) +{ + LM_CELL_DATA *cell_data; + LM_CB_DATA lm_cb_data; + LM_COLUMN_DATA *lm_column_data; + XI_BITMAP *new_bitmap; + + cell_data = &( lmp->cell_data[row][col] ); + lm_cb_data.lm = ( LM ) lmp; + lm_cb_data.cb_type = LM_CB_TEXT; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) row; + lm_cb_data.rec = lmp->recs[row]; + lm_cb_data.column = ( unsigned char ) col; + lm_column_data = lmp->lm_column_data[col]; + if ( xi_text_buffer_size_get( cell_data->xi_text ) ) + { + lmp->cell_request_text = XinMemoryAlloc( xi_text_buffer_size_get( cell_data->xi_text ) ); + strcpy( lmp->cell_request_text, xi_text_get( cell_data->xi_text ) ); + } + lm_cb_data.v.text.text = xi_text_get( cell_data->xi_text ); + lm_cb_data.v.text.len = xi_text_buffer_size_get( cell_data->xi_text ); + if ( lm_cb_data.v.text.text ) + lm_cb_data.v.text.text[0] = '\0'; + lm_cb_data.v.text.font = NULL; + lm_cb_data.v.text.font_id = NULL; + lm_cb_data.v.text.icon_rid = cell_data->icon_rid; + lm_cb_data.v.text.bitmap = cell_data->bitmap; + lm_cb_data.v.text.attrib = cell_data->attrib; + lm_cb_data.v.text.color = 0; + lm_cb_data.v.text.back_color = 0; + lmp->in_cell_request = TRUE; + lmp->cell_request_row = row; + lmp->cell_request_col = col; + ( *lmp->lm_cb ) ( &lm_cb_data ); + cell_data->icon_rid = lm_cb_data.v.text.icon_rid; + new_bitmap = xi_bitmap_copy( lm_cb_data.v.text.bitmap ); + xi_bitmap_destroy( cell_data->bitmap ); + cell_data->bitmap = new_bitmap; + cell_data->attrib = lm_cb_data.v.text.attrib; + cell_data->color = lm_cb_data.v.text.color; + cell_data->back_color = lm_cb_data.v.text.back_color; + if ( lm_column_data->var_len_text && + lm_cb_data.v.text.text != xi_text_get( cell_data->xi_text )) + { + /* The callback func reallocated the string, so the old pointer is simply not valid. */ + xi_text_buffer_set( cell_data->xi_text, lm_cb_data.v.text.text ); + xi_text_reinitialize( cell_data->xi_text ); + } + if ( lm_cb_data.v.text.len != xi_text_buffer_size_get( cell_data->xi_text ) ) + xi_text_buffer_size_set( cell_data->xi_text, lm_cb_data.v.text.len ); + if ( lmp->cell_request_text && strcmp( xi_text_get( cell_data->xi_text ), lmp->cell_request_text ) != 0 ) + xi_text_wrap( cell_data->xi_text ); + if ( lmp->cell_request_text ) + XinMemoryFree( lmp->cell_request_text ); + lmp->in_cell_request = FALSE; + lmp->cell_request_text = NULL; + cell_data->valid_data = TRUE; + lm_focus_cell_text_set( lmp, preserve_focus_text, lm_cb_data.v.text.text, row, col, FALSE ); +#if XIWS != XIWS_WM + /* cell buttons not supported for XVT/CH */ + cell_data->button = lm_cb_data.v.text.button; + cell_data->button_on_left = lm_cb_data.v.text.button_on_left; + cell_data->button_on_focus = lm_cb_data.v.text.button_on_focus; + cell_data->button_full_cell = lm_cb_data.v.text.button_full_cell; + cell_data->button_icon_rid = lm_cb_data.v.text.button_icon_rid; + new_bitmap = xi_bitmap_copy( lm_cb_data.v.text.button_bitmap ); + xi_bitmap_destroy( cell_data->button_bitmap ); + cell_data->button_bitmap = new_bitmap; +#endif + if ( cell_data->font ) + XinFontDestroy( cell_data->font ); + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + if ( lm_cb_data.v.text.font ) + XinFontCopy( &cell_data->font, lm_cb_data.v.text.font ); + else + cell_data->font = NULL; + } +#ifdef XI_USE_XVT + else + { + if ( lm_cb_data.v.text.font_id ) + cell_data->font = XinFontXvtConvert( lm_cb_data.v.text.font_id ); + else + cell_data->font = NULL; + } +#endif + if ( cell_data->font != NULL ) + XinWindowFontMap( lmp->win, cell_data->font ); + if ( cell_data->font ) + xi_text_font_set( cell_data->xi_text, cell_data->font ); + else if ( lmp->font ) + xi_text_font_set( cell_data->xi_text, lmp->font ); + else + xi_text_font_set( cell_data->xi_text, xi_get_system_font( ) ); + lm_xi_text_set_color_and_attrib( lmp, lm_column_data, cell_data, row ); + if ( lm_column_data->wrap_text ) + xi_text_wrap( cell_data->xi_text ); + if ( !preserve_focus_text ) + { + int frow, + fcol; + BOOLEAN fis_scrolled; + + lm_focus_cell_get( lmp, &frow, &fcol, &fis_scrolled ); + if ( frow == row && fcol == col ) + { + lmp->focus_state->focus_cell_attrib = cell_data->attrib; + if ( lmp->focus_state->focus_cell_font ) + { + XinFontDestroy( lmp->focus_state->focus_cell_font ); + lmp->focus_state->focus_cell_font = NULL; + } + if ( cell_data->font ) + { + XinFontCopy( &lmp->focus_state->focus_cell_font, cell_data->font ); + } + lmp->focus_state->focus_cell_color = cell_data->color; + lmp->focus_state->focus_cell_back_color = cell_data->back_color; + lmp->focus_state->button = cell_data->button; + lmp->focus_state->button_full_cell = cell_data->button_full_cell; + lmp->focus_state->button_on_left = cell_data->button_on_left; + lmp->focus_state->button_icon_rid = cell_data->button_icon_rid; + lmp->focus_state->button_bitmap = cell_data->button_bitmap; + } + } +} + + +/*------------------------------------------------------------------------- +function: lm_get_attrib +lm: current lm +lm_part: may be LM_LIST, LM_ROW, LM_COLUMN, or LM_CELL +returns: attribute +notes: all rows are +-------------------------------------------------------------------------*/ +unsigned long +lm_get_attrib( LM lm, LM_PART lm_part, int idx, int idx2, + BOOLEAN v_scrolled ) +{ + LM_DATA *lmp = LMP( lm ); + + switch ( lm_part ) + { + case LM_LIST: + return ( lmp->attrib ); + case LM_ROW: + if ( v_scrolled ) + return lm_focus_rec_attrib_get( lmp ); + else + return ( lmp->row_attribs[idx] ); + case LM_COLUMN: + return ( lmp->lm_column_data[idx]->attrib ); + case LM_CELL: + { + LM_CELL_DATA *cell_data; + + /* TODO this used to test lm_focus_state_get also */ + if ( v_scrolled ) + return lm_focus_cell_attrib_get( lmp ); + cell_data = &lmp->cell_data[idx][idx2]; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, idx, idx2, TRUE ); + return ( cell_data->attrib ); + } + } + XinError( 20907, XinSeverityFatal, 0L ); + return 0L; +} + + +/*------------------------------------------------------------------------- +function: lm_get_buf_size +lm: current lm +part: must be LM_COLUMN +idx: column number +-------------------------------------------------------------------------*/ +int +lm_get_buf_size( LM lm, LM_PART part, int idx ) +{ + LM_DATA *lmp = LMP( lm ); + + NOREF( part ); + return ( lmp->lm_column_data[idx]->text_size ); +} + + +/*------------------------------------------------------------------------- +function: lm_get_cid +lm: current lm +returns: control id of list +-------------------------------------------------------------------------*/ +int +lm_get_cid( LM lm ) +{ + LM_DATA *lmp = LMP( lm ); + + return lmp->cid; +} + + +/*------------------------------------------------------------------------- +function: lm_get_rect +lm: current lm +part: may be LM_LIST, LM_COLUMN, or LM_ROW +idx: if LM_LIST, not used + if LM_COLUMN, column number + if LM_ROW, row number +rct: rectangle to be filled in +returns: rct +-------------------------------------------------------------------------*/ +XinRect * +lm_get_rect( LM lm, LM_PART part, int idx, XinRect * rct ) +{ + LM_DATA *lmp = LMP( lm ); + + switch ( part ) + { + case LM_LIST: + *rct = lmp->rct; + if ( lmp->pixel_width ) + rct->right = rct->left + lmp->pixel_width + 2 * BORDER_WIDTH; + break; + case LM_COLUMN: + { + LM_COLUMN_DATA *column_data; + + column_data = lmp->lm_column_data[idx]; + if ( idx >= lmp->fixed_columns ) + rct->left = lmp->rct.left + column_data->x_pix_pos - lmp->delta_x; + else + rct->left = lmp->rct.left + column_data->x_pix_pos; + rct->right = rct->left + column_data->pix_width + + 2 * ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + rct->top = lmp->rct.top; + rct->bottom = lmp->rct.bottom; + break; + } + case LM_ROW: + { + int con; + + con = lmp->rrr_offset + lmp->mlr.top; + + rct->top = lmp->pix_offsets[idx] + con; + rct->bottom = rct->top + lmp->pix_heights[idx]; + + rct->left = lmp->rct.left; + rct->right = lmp->rct.right; + break; + } + default: + break; + } + return rct; +} + + +/*------------------------------------------------------------------------- +function: lm_get_text +lm: current lm +s: string to be filled in + NULL is valid +len: size of string to be filled in + if the length of the text is longer than the size of the buffer s, + then len-1 characters will be copied, and s[len-1] will be set + to '\0' +row: row number of cell +column: column number of cell +returns: s +-------------------------------------------------------------------------*/ +char * +lm_get_text( LM lm, char *s, int len, int row, int column, + BOOLEAN v_scrolled ) +{ + LM_DATA *lmp = LMP( lm ); + char *b; + + if ( row == LM_HEADING_TEXT ) + b = lmp->lm_column_data[column]->heading_text; + /* TODO this used to test lm_focus_state_get also */ + else if ( v_scrolled ) + b = lm_focus_cell_text_get( lmp ); + else + { + LM_CELL_DATA *cell_data; + + if ( row >= lmp->nbr_realized_rows || column >= lmp->nbr_columns ) + { + XinError( 20908, XinSeverityWarning, 0L ); + b = NULL; + } + else + { + cell_data = &lmp->cell_data[row][column]; + if ( !cell_data->valid_data ) + { + do_lm_cb_text( lmp, row, column, TRUE ); + b = xi_text_get( cell_data->xi_text ); + } + else + { + /* If we're currently in a cell request, xi_text_get( + * cell_data->xi_text ) will return "". */ + if ( LM_REQUESTING_CELL( lm, row, column ) ) + b = lmp->cell_request_text; + else + b = xi_text_get( cell_data->xi_text ); + } + } + } + if ( s && b ) + { + tstrncpy( s, b, len ); + return s; + } + else + return b; +} + + +/*------------------------------------------------------------------------- +function: lm_get_sel +lm: current lm +c1: pointer to integer to contain selection start +c2: pointer to integer to contain selection stop +-------------------------------------------------------------------------*/ +void +lm_get_sel( LM lm, int *c1, int *c2 ) +{ + lm_focus_cell_selection_get( ( LM_DATA * ) lm, c1, c2 ); +} + + +/*------------------------------------------------------------------------- +function: lm_invalidate_rows_internal +lm: current lm +row_start: starting row +row_end: ending row +redraw: if TRUE, then redraw the rows +column: if -1, then do for all columns + if set, then do for a specific column +-------------------------------------------------------------------------*/ +void +lm_invalidate_rows_internal( LM lm, int row_start, int row_end, + BOOLEAN redraw, int column, + BOOLEAN preserve_focus_text ) +{ + int row, + col; + XinRect rct1, + rct2; + LM_DATA *lmp = LMP( lm ); + int focus_row, + focus_column; + BOOLEAN v_scrolled, + has_focus, + optimize; + + row_end = min( row_end, lmp->nbr_realized_rows - 1 ); + if ( row_start > row_end || row_start < 0 ) + return; + has_focus = lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + optimize = xi_get_pref( XI_PREF_OPTIMIZE_CELL_REQUESTS ) != 0; + for ( row = row_start; row <= row_end; row++ ) + { + for ( col = ( column == -1 ) ? 0 : column; + col < ( ( column == -1 ) ? ( lmp->nbr_columns ) : ( column + 1 ) ); + col++ ) + { + if ( optimize ) + { + /* if the cell that we are doing cell request for has focus, and we are + * not supposed to preserve focus text, then we need to call + * do_lm_cb_text so that the focus cell text will be set to the new + * value so that when we restart editing, the correct value will be in + * the edit control. */ + if ( has_focus && !v_scrolled && !preserve_focus_text && row == focus_row && col == focus_column ) + do_lm_cb_text( lmp, row, col, preserve_focus_text ); + else + { + LM_CELL_DATA *cell_data; + + cell_data = &( lmp->cell_data[row][col] ); + cell_data->valid_data = FALSE; + } + } + else + { + do_lm_cb_text( lmp, row, col, preserve_focus_text ); + } + } + } + if ( redraw ) + { + if ( ( column == -1 ) && ( row_start == 0 ) && + ( row_end == lmp->nbr_realized_rows - 1 ) ) + { + lm_get_row_rect( &rct1, lm, row_start ); + lm_get_row_rect( &rct2, lm, row_end ); + rct1.bottom = rct2.bottom; + lm_invalidate_rect( lmp, &rct1, FALSE ); + } + else + { + int col_start, + col_end; + + if ( column == -1 ) + { + col_start = 0; + col_end = lmp->nbr_columns - 1; + } + else + col_start = col_end = column; + draw_cell_range( lmp, row_start, row_end, col_start, + col_end, FALSE ); + } + } +} + + +/*------------------------------------------------------------------------- +function: lm_invalidate_rows +lm: current lm +row_start: starting row +row_end: ending row +redraw: if TRUE, then redraw the rows +-------------------------------------------------------------------------*/ +void +lm_invalidate_rows( LM lm, int row_start, int row_end, BOOLEAN redraw ) +{ + lm_invalidate_rows_internal( lm, row_start, row_end, redraw, -1, TRUE ); +} + + + + +/*------------------------------------------------------------------------- +function: lm_set_color +lm: current lm +part: must be LM_ROW, or LM_CELL +idx: if LM_ROW, row number + if LM_CELL, row number +idx2: if LM_ROW, not used + if LM_CELL, column number +color: color to set +half_baked: if set, don't redraw +-------------------------------------------------------------------------*/ +void +lm_set_color( LM lm, LM_PART part, int idx, int idx2, BOOLEAN v_scrolled, + XinColor color, BOOLEAN half_baked ) +{ + BOOLEAN do_redraw; + LM_DATA *lmp = LMP( lm ); + + switch ( part ) + { + case LM_ROW: + if ( v_scrolled ) + lm_focus_rec_color_set( lmp, color ); + else + { + do_redraw = ( color != lmp->row_colors[idx] ); + lmp->row_colors[idx] = color; + if ( !half_baked && do_redraw ) + { + XinRect r; + + lm_get_row_rect( &r, lm, idx ); + lm_invalidate_rect( lmp, &r, FALSE ); + } + } + break; + case LM_CELL: + if ( !v_scrolled ) + { + LM_CELL_DATA *cell_data; + + cell_data = &lmp->cell_data[idx][idx2]; + if ( !cell_data->valid_data ) + return; + cell_data->color = color; + } + break; + default: + break; + } +} + + + + +/*------------------------------------------------------------------------- +function: lm_move_to +lmp: current lmp +p: point +-------------------------------------------------------------------------*/ +void +lm_move_to( LM_DATA * lmp, XinPoint p, BOOLEAN adj_v, BOOLEAN adj_h ) +{ + + if ( adj_h ) + { + p.h += lmp->rct.left; + lm_adj_h( lmp, &p.h ); + } + + if ( adj_v ) + lm_adj_v( lmp, p.v ); + + xi_move_to( lmp->win, p ); +} + + +/*------------------------------------------------------------------------- +function: lm_draw_line +lmp: current lmp +p: point +-------------------------------------------------------------------------*/ +void +lm_draw_line( LM_DATA * lmp, XinPoint p, BOOLEAN adj_v, BOOLEAN adj_h ) +{ + if ( adj_h ) + { + p.h += lmp->rct.left; + if ( lm_adj_h( lmp, &p.h ) ) + { + if ( adj_v ) + lm_adj_v( lmp, p.v ); + xi_draw_line( lmp->win, p ); + } + } + else + { + if ( adj_v ) + lm_adj_v( lmp, p.v ); + xi_draw_line( lmp->win, p ); + } +} + +/*------------------------------------------------------------------------- +function: xvtch_draw_line +lmp: current lm pointer +from: from point +to: to point +-------------------------------------------------------------------------*/ +#if XIWS == XIWS_WM +static void +xvtch_draw_line( LM_DATA * lmp, XinPoint * from, XinPoint * to, BOOLEAN adj_h ) +{ + int i, + len; + + char c_v = ( char ) C_V; + char *s, + *s2; + + if ( from->h == to->h ) + { + /* draw vertical line */ + if ( adj_h ) + { + from->h += lmp->rct.left; + if ( lm_adj_h( lmp, &from->h ) ) + { + for ( i = from->v + VPIX_PER_CH; i <= to->v; i += VPIX_PER_CH ) + xi_draw_text( lmp->win, lmp->cur_font, from->h, i, &c_v, 1 ); + } + } + else + { + for ( i = from->v + VPIX_PER_CH; i <= to->v; i += VPIX_PER_CH ) + xi_draw_text( lmp->win, from->h, i, &c_v, 1 ); + } + } + else + { + len = ( to->h - from->h ) / VPIX_PER_CH; + s = xi_tree_malloc( len + 4, NULL ); + s2 = s; + for ( i = 0; i < len; ++i ) + { + + *s2 = C_H; + ++s2; + } + xi_draw_text( lmp->win, from->h, from->v + VPIX_PER_CH, s, len ); + xi_tree_free( s ); + } +} + +#endif + + +#if XIWS == XIWS_WM +static char c_xd, +c_xu, +c_v, +c_xx; + +#endif + + +void +lm_xi_text_prect_get( LM_DATA * lmp, LM_COLUMN_DATA * column_data, + LM_CELL_DATA * cell_data, int row, int col, int col_offset, + int leading, int ascent, int descent, XinRect * rctp ) +{ + XinRect rct, + row_rct; + + lm_get_row_rect( &row_rct, ( LM ) lmp, row ); + /* don't need to test for the rule, it is drawn elsewhere */ +#if XIWS != XIWS_WM + row_rct.bottom--; + if ( row_rct.bottom < row_rct.top ) + row_rct.bottom = row_rct.top; +#endif + lm_get_rect( ( LM ) lmp, LM_COLUMN, col, &rct ); + lm_adj_v( lmp, row_rct.top ); + lm_adj_v( lmp, row_rct.bottom ); + rct.top = row_rct.top; + rct.bottom = row_rct.bottom; + rct.left += col_offset; + rct.right -= col_offset; + if ( !column_data->wrap_text ) + { + if ( column_data->vertical_align_bottom ) + { + int new_top; + +#if XIWS == XIWS_WM + new_top = rct.bottom - ( leading + ascent + descent ); +#else + new_top = rct.bottom - ( leading + ascent + descent ) - 3; +#endif + rct.top = max( rct.top, new_top ); + } + else if ( column_data->vertical_align_center ) + { + int height, + delta, + new_top, + new_bottom; + + height = leading + ascent + descent; + delta = ( rct.bottom - rct.top - height ) / 2; + new_top = rct.top + delta; + new_bottom = rct.bottom - delta; + rct.top = max( rct.top, new_top ); + rct.bottom = min( rct.bottom, new_bottom ); + } + else if ( !column_data->vertical_align_center && !cell_data->button_full_cell ) + { + int new_bottom; + +#if XIWS == XIWS_WM + new_bottom = rct.top + leading + ascent + descent; +#else + new_bottom = rct.top + leading + ascent + descent + 4; +#endif + rct.bottom = min( rct.bottom, new_bottom ); + } + } + if ( cell_data->button ) + { + XinRect r; + + r = rct; + xi_inflate_rect( &r, 1 ); + if ( !cell_data->button_full_cell && ( !cell_data->button_on_focus + || lm_row_has_focus( lmp, row, FALSE ) ) ) + { + if ( cell_data->button_on_left ) + { + r.right = r.left + lmp->pix_row_spacing; + rct.left = r.right; + } + else + { + r.left = r.right - lmp->pix_row_spacing; + rct.right = r.left - ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + } + } + } +#if XIWS != XIWS_WM + rct.top += RULE_Y_OFFSET_TOP; + rct.bottom -= RULE_Y_OFFSET_BOTTOM; +#endif + + if ( column_data->column_well || column_data->column_platform ) + { + rct.left++; + rct.right--; + } + *rctp = rct; +} + + +/*------------------------------------------------------------------------- +function: redraw_cell +lm: current lm +row: +col: +update: if TRUE, redraw_cell is being called due to an XinEventPaint event. +clip_rct: clip rectangle +-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +/* redraw_cell */ +/*-------------------------------------------------------------------------*/ +void +redraw_cell( LM lm, int row, int col, BOOLEAN update ) +{ + draw_cell_range( ( LM_DATA * ) lm, row, row, col, col, update ); +} + +/*-------------------------------------------------------------------------*/ +/* lm_redraw_row */ +/*-------------------------------------------------------------------------*/ +void +lm_redraw_row( LM_DATA * lmp, int row, BOOLEAN update ) +{ + draw_cell_range( lmp, row, row, 0, lmp->nbr_columns - 1, update ); +} + + + +/*------------------------------------------------------------------------- +function: lm_hit_test +lm: current lm +ep: xvt event +oevt: original xvt event, without virtual space coordinate conversions +rowp: if set, to be filled in with the results of the row hit test +columnp: if set, to be filled in with the results of the column hit test +is_vis: row is fully visible +is_part_vis:row is partially visible +returns: 0 - no hit + 1 - hit + 5 - hit on cell button +-------------------------------------------------------------------------*/ +int +lm_hit_test( LM lm, XinEvent * ep, XinEvent * oevt, int *rowp, int *columnp, + BOOLEAN * is_vis, BOOLEAN * is_hit, BOOLEAN * is_part_vis ) +{ + int row, + column, + temp, + col_offset, + tmp_v, + i, + first, + last; + int *pix_offsetsp, + *pix_heightsp; + LM_DATA *lmp = LMP( lm ); + XinPoint where; + + if ( is_vis ) + *is_vis = TRUE; + if ( is_hit ) + *is_hit = FALSE; + if ( is_part_vis ) + *is_part_vis = FALSE; + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + where = ep->v.mouse.where; + + /* if the mouse is to the left or the right of the list, return 0 */ + if ( oevt->v.mouse.where.h < 0 ) + return 0; + if ( lmp->pixel_width && + ( oevt->v.mouse.where.h > ( lmp->rct.left + lmp->pixel_width + + BORDER_WIDTH ) ) ) + return 0; + + /* if the mouse is in the column headings */ + if ( where.v > lmp->pix_top && where.v < lmp->pix_row1_top ) + { + for ( column = 0; column < lmp->nbr_columns; column++ ) + { + LM_COLUMN_DATA *column_data; + + column_data = lmp->lm_column_data[column]; + temp = column_data->x_pix_pos + col_offset; + if ( where.h >= temp && where.h < temp + column_data->pix_width ) + { + *rowp = -1; + *columnp = column; + return 1; + } + } + return 0; + } + + /* if the mouse is above the list, return 0 */ + if ( where.v < lmp->pix_row1_top ) + return 0; + + /* figure out what row the mouse is in */ + tmp_v = where.v - lmp->mlr.top - lmp->rrr_offset; + first = max( lmp->first_fully_vis - 1, 0 ); + last = min( lmp->last_fully_vis + 1, lmp->nbr_realized_rows - 1 ); + for ( i = first, + pix_offsetsp = &lmp->pix_offsets[i], + pix_heightsp = &lmp->pix_heights[i]; + i <= last; ++i, ++pix_offsetsp, ++pix_heightsp ) + { + if ( tmp_v >= *pix_offsetsp && tmp_v < ( *pix_offsetsp + *pix_heightsp ) ) + { + row = i; + break; + } + } + if ( i > last ) + { + if ( is_vis ) + *is_vis = FALSE; + return 0; + } + if ( is_vis ) + { + if ( i < lmp->first_fully_vis || i > lmp->last_fully_vis ) + { + *is_vis = FALSE; + if ( ( i == lmp->last_fully_vis + 1 ) && ( ep->v.mouse.where.v < lmp->mlr.bottom ) ) + { + if ( is_part_vis ) + *is_part_vis = TRUE; + } + } + else + *is_vis = TRUE; + } + else if ( i < lmp->first_fully_vis || i > lmp->last_fully_vis ) + return 0; + for ( column = 0; column < lmp->nbr_columns; column++ ) + { + LM_COLUMN_DATA *column_data; + + column_data = lmp->lm_column_data[column]; + temp = column_data->x_pix_pos + col_offset; + if ( where.h >= temp && where.h < temp + column_data->pix_width ) + { + if ( ( ( lmp->attrib & ( LM_ATR_ENABLED | LM_ATR_VISIBLE ) ) == ( LM_ATR_ENABLED | LM_ATR_VISIBLE ) ) + && ( lmp->lm_column_data[column]->attrib & ( LM_COL_ATR_ENABLED | LM_COL_ATR_SELECTABLE ) ) ) + { + LM_CELL_DATA *cell_data; + + *rowp = row; + *columnp = column; + if ( is_hit ) + *is_hit = TRUE; + cell_data = &lmp->cell_data[row][column]; + if ( cell_data->button ) + { + XinRect outer_rct; + XinPoint p; + + lm_get_cell_rect( &outer_rct, lm, row, column, FALSE, FALSE ); + xi_inflate_rect( &outer_rct, 1 ); + if ( !cell_data->button_full_cell ) + { + if ( cell_data->button_on_left ) + outer_rct.right = outer_rct.left + lmp->pix_row_spacing; + else + outer_rct.left = outer_rct.right - lmp->pix_row_spacing; + } + p = ep->v.mouse.where; + p.v = tmp_v; + if ( xi_pt_in_rect( &outer_rct, p ) ) + { + return 5; + } + } + else if ( lm_focus_cell_has( lmp, row, column, FALSE ) ) + { + XinRect outer_rct; + XinPoint p; + + lm_get_cell_rect( &outer_rct, lm, row, column, FALSE, FALSE ); + xi_inflate_rect( &outer_rct, 1 ); + if ( cell_data->xi_text ) + xi_text_rect_get_adjusted( cell_data->xi_text, &outer_rct ); + p = ep->v.mouse.where; + p.v = tmp_v; + if ( !xi_pt_in_rect( &outer_rct, p ) ) + { + return 0; + } + } + return 1; + } + else + { + *rowp = row; + *columnp = column; + if ( is_hit ) + *is_hit = TRUE; + if ( is_part_vis ) + *is_part_vis = FALSE; + return 0; + } + } + } + if ( is_part_vis ) + *is_part_vis = FALSE; + return 0; +} + +/*------------------------------------------------------------------------- +function: lm_set_font +lm: current lm +part: must be LM_COLUMN, or LM_CELL +idx: column number +idx2: if LM_CELL, row number +font: font to set +-------------------------------------------------------------------------*/ +void +lm_set_font( LM lm, LM_PART part, int idx, int idx2, XinFont * font ) +{ + LM_DATA *lmp = LMP( lm ); + LM_CELL_DATA *cell_data; + + switch ( part ) + { + case LM_COLUMN: + { + LM_COLUMN_DATA *lmcd; + XinRect rct; + + lmcd = lmp->lm_column_data[idx]; + if ( lmcd->font ) + XinFontDestroy( lmcd->font ); + if ( font ) + XinFontCopy( &lmcd->font, font ); + else + lmcd->font = NULL; + lm_get_rect( lm, LM_COLUMN, idx, &rct ); + lm_invalidate_rect( lmp, &rct, TRUE ); + break; + } + case LM_CELL: + { + cell_data = &lmp->cell_data[idx][idx2]; + if ( cell_data->font ) + XinFontDestroy( cell_data->font ); + if ( font ) + XinFontCopy( &cell_data->font, font ); + else + cell_data->font = NULL; + if ( cell_data->font != NULL ) + XinWindowFontMap( lmp->win, cell_data->font ); + break; + } + default: + break; + } +} + + +/*********************************************************************/ + +/* LM drawing functions */ + +#if 0 +/*------------------------------------------------------------------------- +function: lm_set_clip +lmp: current lmp +rctp: clipping rectangle +-------------------------------------------------------------------------*/ +static void +lm_set_clip( LM_DATA * lmp, XinRect * rctp ) +{ + XinRect r; + + r = *rctp; + r.left += lmp->rct.left; + r.right += lmp->rct.left; + + lm_adj_h( lmp, &r.left ); + lm_adj_h( lmp, &r.right ); + + xi_set_clip( lmp->win, &r ); +} + +#endif + +/*------------------------------------------------------------------------- +function: lm_draw_text +lmp: current lmp +h: h position +v: v position +s: string +len: length of string +-------------------------------------------------------------------------*/ +#if XIWS == XIWS_WM +static void +lm_draw_text( LM_DATA * lmp, int h, int v, char *s, int len ) +{ + short sh; + + sh = h; + sh += lmp->rct.left; + if ( lm_adj_h( lmp, &sh ) ) + { + lm_adj_v( lmp, v ); + xi_draw_text( lmp->win, sh, v, s, len ); + } +} + +#endif + + + + + +/* +Make it so a row can have the focus. +Tab will move focus to a cell in the row, if there is a cell in the row + that can take focus. +If XI_ATR_SELECTABLE is set for any columns, space will select the + row. +Up arrow and down arrow work. If the focus is on a cell, the focus stays + on a cell. If the focus is on a row, the focus stays on a row. +Page up and down should work. +If the focus is on the last editable cell, and tab_wrap is set, then the + focus moves to the next row. +If the focus is + the focus move to the current row. +Have an option on a list by list basis, enter selects if a row has the + focus. Enter will act like a double click selection. +If the row focus option is set, put up the other hand cursor. + +possibly revisit how text is stored in cells - may want indefinite buffer + size for a column. +when entering text in a cell, continually evaluate the correct height of + the cell. The function to recalc number of rows and break points should + compare line by line, until there is a difference, then do detailed + comparison after the difference. +it should be possible to scroll the list backwards to gain more room above + if the cell is at the bottom of the list +if the cell is already the maximum possible height, then not necessary to + do any more comparisons +limit text edit to buffer size +make sure that the clipboard works + +TODO in the future +------------------ +if height is 0, make the list height be the same as the window height +expose lm drawing functions +xi_set_icon for buttons +make an option so that when the user tabs to an edit control that already contains text, the + insertion point is set to the right of the text. +settable background color for text on a 3d radio button or check box, (tab buttons also) +make function xi_is_nav_char +make readonly cells +need colors for static text +want ability on XVT/CH to have single character fields. Eliminate the [ and ]. +*/ + +void +set_focus_cell_rct( LM_DATA * lmp, int row, int col, BOOLEAN in_update_event ) +{ + LM_CELL_DATA *cell_data; + LM_COLUMN_DATA *column_data; + int leading, + ascent, + descent; + int col_offset; + XinRect rct; + XinRect mlr = lmp->mlr; + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + + cell_data = &lmp->cell_data[row][col]; + column_data = lmp->lm_column_data[col]; + + if ( cell_data->font ) + XinFontMetricsGet( cell_data->font, &leading, &ascent, &descent ); + else + XinFontMetricsGet( lmp->font, &leading, &ascent, &descent ); + + lm_xi_text_prect_get( lmp, column_data, cell_data, row, col, col_offset, leading, + ascent, descent, &rct ); + xi_text_prect_set( cell_data->xi_text, &rct ); + if ( lmp->pixel_width ) + mlr.right = mlr.left + lmp->pixel_width; + xi_text_clip_set( cell_data->xi_text, &mlr ); + if ( xi_text_editing_is( cell_data->xi_text ) ) + xi_text_draw( cell_data->xi_text, 0L, 0L, in_update_event ); +} + +XI_TEXT * +lm_xi_text_focus_get( LM lm ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + int row, + col; + BOOLEAN is_vert; + LM_CELL_DATA *cell_data; + + if ( !lm_focus_cell_get( lmp, &row, &col, &is_vert ) ) + return NULL; + if ( is_vert ) + return NULL; + cell_data = &( lmp->cell_data[row][col] ); + return cell_data->xi_text; +} diff --git a/src/xi01/xilm.h b/src/xi01/xilm.h new file mode 100644 index 000000000..92b8f358c --- /dev/null +++ b/src/xi01/xilm.h @@ -0,0 +1,679 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +/****************************************************************** +LM module +******************************************************************/ +#define LM_ATR_ENABLED XI_ATR_ENABLED + +#define LM_ATR_VISIBLE XI_ATR_VISIBLE +#define LM_ATR_NAVIGATE XI_ATR_NAVIGATE +#define LM_ATR_TABWRAP XI_ATR_TABWRAP +/*------------------------------------------------------------------------- +function: lm_adj_v +lmp: current lmp +v: to vertical coord to convert +-------------------------------------------------------------------------*/ +#define lm_adj_v(lmp, v) (v = v + lmp->mlr.top + lmp->rrr_offset) + +typedef enum _lm_cb_type +{ + LM_CB_CHAR, + LM_CB_CHANGE, + LM_CB_DBL, + LM_CB_FOCUS, + LM_CB_TEXT, + LM_CB_SELECT, + LM_CB_CELL_BTN, + LM_CB_GET_FIRST, + LM_CB_GET_NEXT, + LM_CB_GET_PREV, + LM_CB_GET_LAST, + LM_CB_GET_PERCENT, + LM_CB_REC_ALLOCATE, + LM_CB_REC_FREE, + LM_CB_ROW_SIZE, + LM_CB_COL_DELETE, + LM_CB_COL_MOVE, + LM_CB_COL_SIZE, + LM_CB_DROP_ROW +} + +LM_CB_TYPE; + +typedef struct _lm_cb_data +{ + LM lm; + LM_CB_TYPE cb_type; + int cid; + XinWindow win; + int row; + int column; + long rec; + union + { + struct + { + long spec_rec; + long data_rec; + int percent; + unsigned long attrib; + XinColor color; + BOOLEAN refused; + int row_height; + BOOLEAN has_focus; + } rec_request; + struct + { + int new_row_height; + BOOLEAN refused; + } row_size; + struct + { + long record; + } rec_allocate; + struct + { + long record; + } rec_free; + struct + { + long record; + int percent; + } get_percent; + struct + { + char *text; + int len; + int icon_rid; + XI_BITMAP* bitmap; + unsigned long attrib; + XinColor color; + XinColor back_color; + XinFont *font; + BOOLEAN button; + BOOLEAN button_on_left; + BOOLEAN button_on_focus; + BOOLEAN button_full_cell; + int button_icon_rid; + XI_BITMAP* button_bitmap; + void *font_id; + } text; + BOOLEAN refused; + struct + { + int ch; + BOOLEAN shift; + BOOLEAN control; + BOOLEAN alt; + BOOLEAN is_paste; + BOOLEAN refused; + } chr; + struct + { + BOOLEAN dbl_click; + BOOLEAN selected; + BOOLEAN refused; + BOOLEAN shift; + BOOLEAN control; + int column; + } select; + struct + { + BOOLEAN shift; + BOOLEAN control; + } cell_btn; + struct + { + int new_col_nbr; + BOOLEAN in_fixed; + int new_col_width; + int new_col_pixel_width; + BOOLEAN refused; + } column; + struct + { + XI_OBJ* src_list; + long src_rec; + BOOLEAN after_all_rows; + BOOLEAN delete_row; + BOOLEAN shift; + BOOLEAN control; + } drop_row; + /* nothing for LM_CB_CHANGE */ + } v; +} LM_CB_DATA; + +typedef void ( *LM_CB ) ( LM_CB_DATA * lm_cb_data ); + +#define LM_COL_ATR_ENABLED XI_ATR_ENABLED +#define LM_COL_ATR_EDITMENU XI_ATR_EDITMENU +#define LM_COL_ATR_AUTOSELECT XI_ATR_AUTOSELECT +#define LM_COL_ATR_AUTOSCROLL XI_ATR_AUTOSCROLL +#define LM_COL_ATR_RJUST XI_ATR_RJUST +#define LM_COL_ATR_READONLY XI_ATR_READONLY +#define LM_COL_ATR_PASSWORD XI_ATR_PASSWORD +#define LM_COL_ATR_SELECTED XI_ATR_SELECTED +#define LM_COL_ATR_SELECTABLE XI_ATR_SELECTABLE +#define LM_COL_ATR_COL_SELECTABLE XI_ATR_COL_SELECTABLE +#define LM_COL_ATR_VISIBLE XI_ATR_VISIBLE + +#define LM_ROW_ATR_ENABLED XI_ATR_ENABLED +#define LM_ROW_ATR_SELECTED XI_ATR_SELECTED + +#define LM_CELL_ATR_SELECTED XI_ATR_SELECTED +#define LM_CELL_ATR_RJUST XI_ATR_RJUST +#define LM_CELL_ATR_HCENTER XI_ATR_HCENTER + +typedef struct _lm_column_data +{ + unsigned long attrib; + short pix_width; + short x_pix_pos; + short text_size; + char *heading_text; + short width; + BOOLEAN center_heading; + BOOLEAN heading_well; + BOOLEAN heading_platform; + BOOLEAN column_well; + BOOLEAN column_platform; + XinFont *font; + int icon_rid; + short icon_x; + short icon_y; + XI_BITMAP* bitmap; + BOOLEAN size_rows; + BOOLEAN suppress_update_heading; + BOOLEAN suppress_update_cells; + BOOLEAN vertical_align_center; + BOOLEAN vertical_align_bottom; + BOOLEAN wrap_text; + BOOLEAN wrap_text_scrollbar; + BOOLEAN cr_ok; + BOOLEAN var_len_text; + BOOLEAN auto_tab; + XI_ICON_MODE_TYPE icon_mode; + BOOLEAN pushed; + + /* temporary variables - don't assume this is good */ + XinRect column_rct; /* used for caching column rectangles to speed + * drawing */ + XinRect prct; /* physical rect */ + BOOLEAN XinWindowPaintNeeds; +} LM_COLUMN_DATA; + +typedef struct _lm_column_def +{ + unsigned long attrib; + short position; + short pix_width; /* pixels */ + short text_size; + char *heading_text; + BOOLEAN center_heading; + BOOLEAN heading_well; + BOOLEAN heading_platform; + BOOLEAN column_well; + BOOLEAN column_platform; + XinFont *font; + int icon_rid; + short icon_x; + short icon_y; + XI_BITMAP* bitmap; + BOOLEAN size_rows; + BOOLEAN suppress_update_heading; + BOOLEAN suppress_update_cells; + BOOLEAN vertical_align_center; + BOOLEAN vertical_align_bottom; + BOOLEAN wrap_text; + BOOLEAN wrap_text_scrollbar; + BOOLEAN cr_ok; + BOOLEAN var_len_text; + BOOLEAN auto_tab; + XI_ICON_MODE_TYPE icon_mode; +} LM_COLUMN_DEF; + +typedef struct _lm_def +{ + int cid; + XI_OBJ *list_obj; + XI_OBJ *itf_obj; + + /* XI may specify this */ + XinPoint pnt; + short pixel_height; + /* If absolute height is set, then the height of the list will be exactly + * height pixels high */ + BOOLEAN absolute_height; + short pixel_width; + + short pix_char_width; + unsigned long attrib; + LM_CB lm_cb; + XinFont *font; + BOOLEAN is_list_font; /* False, if "font" is from the interface or system */ + XinColor enabled_color; /* but inactive */ + XinColor back_color; + XinColor disabled_color; + XinColor disabled_back_color; + XinColor active_color; + XinColor active_back_color; + XinColor white_space_color; + XinColor rule_color; + char *parent; + BOOLEAN no_heading; + BOOLEAN one_row_list; + int nbr_rows; + int realized_rows_array_len; + BOOLEAN sizable_columns; + BOOLEAN movable_columns; + short fixed_columns; + short min_cell_height; + short min_heading_height; + BOOLEAN no_horz_lines; + BOOLEAN no_vert_lines; + int first_vis_column; + BOOLEAN drop_and_delete; + BOOLEAN select_cells; + BOOLEAN fixed_row_height; + BOOLEAN sizable_rows; + BOOLEAN get_all_records; + BOOLEAN resize_with_window; + int horz_sync_list; + int vert_sync_list; + BOOLEAN row_focus_border; + XinColor row_focus_border_color; + int max_lines_in_cell; + BOOLEAN single_select; + BOOLEAN retain_back_color_on_select; + BOOLEAN drag_and_drop_rows; + BOOLEAN drag_rows_autoscroll; + BOOLEAN button_on_cell_focus; + int position_by_typing_cid; +} LM_DEF; + +#define LM_HEADING_TEXT 1001 + +typedef enum +{ + LM_LIST, + LM_ROW, + LM_COLUMN, + LM_CELL +} + +LM_PART; + +typedef struct _lm_cell_data +{ + unsigned long attrib; + XinFont *font; + XinColor color; + XinColor back_color; + int icon_rid; + XI_BITMAP* bitmap; + BOOLEAN button; + BOOLEAN button_on_left; + BOOLEAN button_on_focus; + BOOLEAN button_full_cell; + int button_icon_rid; + XI_BITMAP* button_bitmap; + BOOLEAN valid_data; + int font_height; + XI_TEXT *xi_text; +} LM_CELL_DATA; + +typedef struct _lm_data +{ + int cid; + XinWindow win; + XinRect rct; + short pix_top; + short pix_hdr_bottom; + short pix_row1_top; + short pix_char_width; + short pix_cell_height; + short pix_row_spacing; + unsigned long attrib; + short nbr_columns; + LM_COLUMN_DATA **lm_column_data; + XinColor back_color; + XinColor enabled_color; /* but inactive */ + XinColor disabled_color; + XinColor disabled_back_color; + XinColor active_color; + XinColor active_back_color; + XinColor white_space_color; + XinColor rule_color; + BOOLEAN no_heading; + BOOLEAN sizable_columns; + BOOLEAN movable_columns; + short fixed_columns; + short pixel_width; + short pixel_height; + BOOLEAN moving_column; + BOOLEAN sizing_column; + int column_being_sized; + short min_cell_height; + short min_heading_height; + BOOLEAN no_horz_lines; + BOOLEAN no_vert_lines; + BOOLEAN drop_and_delete; + BOOLEAN select_cells; + BOOLEAN selecting_text; + BOOLEAN sizing_row; + BOOLEAN resize_with_window; + int row_being_sized; + int horz_sync_list; + int vert_sync_list; + BOOLEAN row_focus_border; + XinColor row_focus_border_color; + int max_lines_in_cell; + BOOLEAN single_select; + BOOLEAN retain_back_color_on_select; + BOOLEAN drag_and_drop_rows; + BOOLEAN drag_rows_autoscroll; + BOOLEAN button_on_cell_focus; + int position_by_typing_cid; + + /* run time data */ + LM_CB lm_cb; + XI_OBJ *list_obj; + XI_OBJ *itf_obj; + XinFont *font; + BOOLEAN is_list_font; /* False, if "font" is from the interface or system */ + BOOLEAN have_mouse; + int column_being_moved; + int last_x; + int last_y; + BOOLEAN down_in_hscrolling; + BOOLEAN in_hscrolling; + BOOLEAN last_in_hscrolling; + XI_OBJ* last_itf; + int org_x; + int org_y; + int ascent; + int descent; + int leading; + BOOLEAN selecting_cells; + int down_row; + int down_column; + int cur_row; + int cur_column; + BOOLEAN down_on_disabled; + int delta_x; + int first_vis; + int last_vis; + int vir_left; + int vir_right; + BOOLEAN btn_down; /* or up */ + BOOLEAN down_in_btn; + int btn_down_row; + int btn_down_col; + int update_rows_at_top; + int update_rows_at_bottom; + BOOLEAN update_cells_only; + BOOLEAN text_scrolling; + int old_row_height; + BOOLEAN horizontally_scrolling_list; + struct _lm_focus_state *focus_state; + XinFont *cur_font; + BOOLEAN have_last_rec; + long last_rec; + BOOLEAN down_in_heading; + + /* vertical scrolling information */ + XinRect mlr; + int mlr_height; + int rrr_offset; /* offset of mlr */ + int rrr_bottom; /* total number of vertical pixels in realized + * row rect */ + int nbr_rows; /* visible, specified by XI */ + int realized_rows_array_len; /* also specified by XI */ + int nbr_realized_rows; /* number of rows actually used in realized row + * array */ + int first_fully_vis; + int last_fully_vis; + BOOLEAN fixed_row_height; + BOOLEAN sizable_rows; + BOOLEAN get_all_records; + BOOLEAN in_cell_request; /* Hold on to text for a cell, in case application wants */ + int cell_request_row; /* to know what we had last. */ + int cell_request_col; + char *cell_request_text; + + /* the following arrays are all allocated to the length of + * realized_rows_array_len */ + long *recs; + int *pix_offsets; /* pixel offsets of each row */ + int *pix_heights; /* pixel heights of each row */ + BOOLEAN *set_heights; + unsigned long *row_attribs; + XinColor *row_colors; + LM_CELL_DATA **cell_data; + + /* Drag and Drop Rows information */ + XinPoint down_pt; + BOOLEAN down_in_row; + BOOLEAN dragging_row; + long rec_being_moved; + int drag_row_height; + BOOLEAN delay_select; + int delay_row; + int delay_column; + BOOLEAN delay_dbl; + char *position_by_typing_buf; +} LM_DATA; + +#define NULL_LM (LM)0 + + +/* +Activities to test +1. Resize list +2. Resize column +3. Move columns around +4. Add columns +5. Delete columns +6. xi_cell_request +7. Tab around +8. Horizontal scroll +9. Vertical scroll +10. Drop horizontal thumb +11. Drop vertical thumb +12. Select range of cells +13. Set font on range of cells +14. Click on partially vis column +15. Size row +16. Change wrapping of text in cell +*/ + +typedef struct _lm_scroll_arg +{ + LM lm; + int nbr_lines; + int percent; + BOOLEAN same_cell; + long rec; + BOOLEAN have_rec; + XinColor color; + unsigned long attrib; + int row_height; + BOOLEAN rec_at_top; + int pixels_scrolled; /* this is a return value from lm_scroll */ +} LM_SCROLL_ARG; + + +void calculate_pix_offsets( LM_DATA * lmp, BOOLEAN draw_changes ); +void calculate_visibles( LM_DATA * lmp ); +void calc_x_pix_pos( LM lm, LM_COLUMN_DATA * lcdata, int position ); +BOOLEAN +do_lm_cb( LM lm, LM_CB_TYPE cb_reason, int row, int column, + XinEvent * ep, int *percent, int pixels ); +BOOLEAN +do_lm_cb_get( LM lm, LM_CB_TYPE cb_reason, long *spec_rec, + long *data_rec, int percent, XinColor * color, + unsigned long *attrib, int *row_height ); +void do_lm_cb_text( LM_DATA * lmp, int row, int col, BOOLEAN preserve_focus ); +void do_scroll_bar( XI_LIST_DATA * listdata ); +BOOLEAN lm_adj_h( LM_DATA * lmp, short *h ); +void lm_allocate_rec_info( LM_DATA * lmp, int realized_rows_array_len ); +void lm_calc_last_vis( LM_DATA * lmp ); +int lm_calculate_row_height( LM_DATA * lmp, int row ); +void lm_cell_request( LM lm, LM_PART lm_part, int idx1, int idx2 ); +void lm_column_set_pixel_width( LM lm, int idx, int width ); +LM lm_create( XinWindow win, LM_DEF * lm_def, void *parent ); +void +lm_create_column( LM lm, LM_COLUMN_DEF * lm_column_def, + BOOLEAN do_cell_requests, BOOLEAN in_hscrolling ); +void lm_cleanup( LM lm ); +void lm_delete( LM lm ); +void lm_delete_column( LM lm, int column_nbr, BOOLEAN adjust_hscrolling ); +BOOLEAN lm_delete_row( LM lm, int row ); +void lm_draw_line( LM_DATA * lmp, XinPoint p, BOOLEAN adj_v, BOOLEAN adj_h ); +int lm_event( XI_OBJ* itf, LM lm, XinEvent * ep ); +void +lm_focus_cb( long lm, int row, int column, BOOLEAN invisible, + BOOLEAN set ); +unsigned long +lm_get_attrib( LM lm, LM_PART lm_part, int idx, int idx2, + BOOLEAN invisible ); +int lm_get_buf_size( LM lm, LM_PART part, int idx ); +int lm_get_cid( LM lm ); +XinRect * +lm_get_cell_rect( XinRect * rctp, LM lm, int row, int col, BOOLEAN inner, + BOOLEAN physical_rct ); +int lm_get_col_spacing( void ); +int lm_get_fixed_columns( LM lm ); +int lm_get_left_most_far_right_col( LM_DATA * lmp, int nbr_columns ); +long *lm_get_list_info( LM lm, int *nbr_recs ); +XI_OBJ *lm_get_list_obj( LM lm ); +XinRect *lm_get_list_rct( LM_DATA * lmp, XinRect * r ); +void +lm_get_metrics( XI_OBJ_DEF * obj_def, int *hborder, int *column_div, + int *list_bottom ); +XinRect *lm_get_rect( LM lm, LM_PART part, int idx, XinRect * rct ); +XinRect *lm_get_row_rect( XinRect * rctp, LM lm, int row ); +void lm_get_sel( LM lm, int *c1, int *c2 ); +char * +lm_get_text( LM lm, char *s, int len, int row, int column, + BOOLEAN invisible ); +void +lm_get_vertical_metrics( XI_OBJ_DEF * obj_def, int *first_row_y, + int *row_spacing, int *client_height, + int *title_height ); +void lm_get_visible_columns( LM lm, int *first_vis, int *last_vis ); +int lm_get_visible_rows( LM lm, int *first_vis, int *last_vis ); +int lm_hit_test( LM lm, XinEvent* ep, XinEvent* oevt, int* rowp, int* columnp, + BOOLEAN* is_vis, BOOLEAN* is_hit, BOOLEAN* is_part_vis ); +void lm_hscroll( LM lm, int nbr_columns, int pos ); +BOOLEAN lm_insert_row( LM lm, int row ); + +void lm_invalidate_rect( LM_DATA * lmp, XinRect * rctp, BOOLEAN adj_h ); +void +lm_invalidate_rect2( LM_DATA * lmp, XinRect * rct_to_invalidate, + BOOLEAN adj_left ); +void +lm_invalidate_rows( LM lm, int row_start, int row_end, + BOOLEAN invalidate ); +void +lm_invalidate_rows_internal( LM lm, int row_start, int row_end, + BOOLEAN redraw, int column, + BOOLEAN preserve_focus_text ); +void lm_local_hscroll( LM lm, int nbr_columns ); +void lm_move_event( LM_DATA * lmp, XinEvent * ep ); +void lm_drag_row_event( XI_OBJ* itf, LM_DATA* lmp, XinEvent* ep, XinEvent* oevp ); +void lm_move_to( LM_DATA * lmp, XinPoint p, BOOLEAN adj_v, BOOLEAN adj_h ); +void lm_recalc_metrics( LM lm ); +void lm_redraw_row( LM_DATA * lmp, int row, BOOLEAN update ); +void lm_remove_all_rows( LM_DATA * lm, BOOLEAN delete_focus ); +BOOLEAN lm_row_has_focus( LM_DATA * lmp, int row, BOOLEAN is_vert_scrolled ); +int lm_scroll( LM_SCROLL_ARG * arg ); +void lm_scroll_rect( LM_DATA * lmp, XinRect * rctp, int dh, int dv ); +void lm_set_fixed_columns( LM lm, int new_fixed_count ); +void +lm_set_attrib( LM lm, LM_PART lm_part, int idx, int idx2, + BOOLEAN invisible, unsigned long attrib, + int half_baked ); +void lm_set_buf_size( LM lm, LM_PART part, int idx, int size ); +void lm_set_column_bitmap( LM lm, XI_BITMAP* bitmap, int cid ); +void lm_set_column_icon( LM lm, int icon_rid, int cid ); +void lm_set_column_width( LM lm, int idx, int width ); +void +lm_set_color( LM lm, LM_PART part, int row, int column, + BOOLEAN invisible, XinColor color, BOOLEAN half_baked ); +void lm_set_fixed_columns( LM lm, int new_fixed_count ); +void lm_set_hscroll_bar( LM lm ); +void lm_set_hscroll_range( LM lm ); +void lm_set_bitmap( LM lm, XI_BITMAP* bitmap, int row, int column ); +void lm_set_icon( LM lm, int icon_rid, int row, int column ); +void lm_set_focus( LM lm, int row, int column ); +void lm_set_font( LM lm, LM_PART part, int idx, int idx2, XinFont * font ); +void lm_set_list_size( LM lm, int height, int width ); +void lm_set_rect( LM lm, XinRect *rect ); +void +lm_set_row_height( LM lm, int row, int height, BOOLEAN set_height, + int old_height, BOOLEAN only_update ); +void +lm_set_sel( LM lm, int row, int column, BOOLEAN invisible, int c1, + int c2 ); +void lm_set_text( LM lm, const char *s, int row, int column, BOOLEAN invisible ); +void lm_size_event( LM_DATA * lmp, XinEvent * ep ); +void lm_text_scrolling( XI_OBJ * xi_obj ); +void lm_wrap_text( LM_DATA * lmp, int row, int col, BOOLEAN set_font ); +int lm_make_rrr_room_pix( LM_DATA * lmp, int pixels, BOOLEAN do_redraw ); +BOOLEAN navigate_char_event( LM lm, XinEvent * ep ); +void redraw_cell( LM lm, int row, int col, BOOLEAN update ); +void +draw_cell_range( LM_DATA * lmp, int first_row, int last_row, + int first_col, int last_col, + BOOLEAN in_event_update ); +XinRect *lm_get_scroll_rct( LM_DATA * lmp, XinRect * r ); +void lm_do_rec_event( LM_DATA * lmp, int row, XI_EVENT_TYPE type ); +void lm_row_copy( LM_DATA * lmp, int source_row, int dest_row ); +void lm_adjust_rows( LM_DATA * lmp, int delta ); +void set_focus_cell_rct( LM_DATA * lmp, int row, int col, BOOLEAN in_update_event ); +XI_TEXT *lm_xi_text_focus_get( LM lm ); +void lm_calculate_pix_offsets( LM lm ); +void lm_xi_text_prect_get( LM_DATA * lmp, LM_COLUMN_DATA * column_data, + LM_CELL_DATA * cell_data, int row, int col, int col_offset, + int leading, int ascent, int descent, XinRect * rctp ); +BOOLEAN lm_cr_is_ok( LM lm, int row, int col, BOOLEAN v_scrolled ); +BOOLEAN lm_is_button_full_cell( LM lm, int row, int col ); +void lm_xi_text_construct( LM_DATA * lmp, int row, int column ); + +#define LMP(l) ((LM_DATA *)(l)) + +#if XIWS == XIWS_WM +#define RULE_Y_OFFSET_TOP 0 +#define RULE_Y_OFFSET_BOTTOM 0 +#define BORDER_WIDTH 8 +#define RULE_WIDTH_V 8 /* width of vertical lines */ +#define RULE_WIDTH_H 0 /* width of horz lines */ +#define HPIX_PER_CH 8 +#define VPIX_PER_CH 8 +#else +#define RULE_Y_OFFSET_TOP 1 +#define RULE_Y_OFFSET_BOTTOM 1 +#define BORDER_WIDTH 2 +#define RULE_WIDTH_V 1 +#define RULE_WIDTH_H 1 +#define WIDTHLOOP(idx, wid) for (idx = 0; idx < wid; idx++) +#endif + +#define CELL_IS_ENABLED(lm, row, col) (LIST_IS_ENABLED(lm) && COLUMN_IS_ENABLED(lm, col)) +#define CELL_IS_SELECTED(lm, row, col) ((LMP(lm)->row_attribs[row] & LM_ROW_ATR_SELECTED) || (LMP(lm)->lm_column_data[col]->attrib & LM_COL_ATR_SELECTED) || \ + (LMP(lm)->cell_data[row][col].attrib & LM_CELL_ATR_SELECTED)) +#define CELL_IS_SELECTABLE(lm, row, col) (LMP(lm)->lm_column_data[col]->attrib & LM_COL_ATR_SELECTABLE) +#define LIST_IS_ENABLED(lm) ((LMP(lm)->attrib & (LM_ATR_ENABLED | LM_ATR_VISIBLE)) == (LM_ATR_ENABLED | LM_ATR_VISIBLE)) +#define COLUMN_IS_ENABLED(lm, col) (LMP(lm)->lm_column_data[col]->attrib & LM_COL_ATR_ENABLED) +#define COLUMN_IS_SELECTABLE(lm, col) (LMP(lm)->lm_column_data[col]->attrib & LM_COL_ATR_COL_SELECTABLE) +#define COLUMN_IS_SELECTED(lm, col) (LMP(lm)->lm_column_data[col]->attrib & LM_COL_ATR_SELECTED) +#define COLUMN_IS_PUSHED(lm, col) (LMP(lm)->lm_column_data[col]->pushed) diff --git a/src/xi01/xilm2.c b/src/xi01/xilm2.c new file mode 100644 index 000000000..581bf5bea --- /dev/null +++ b/src/xi01/xilm2.c @@ -0,0 +1,5291 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#include "xi.h" +#include "xitext.h" +#include "xilm.h" +#include "xilmst.h" +#include "xiutils.h" +#include "xidisply.h" +#include "xi_int.h" +#include + +#define REALIZED_ROWS_GRANULE 4 +#define REC_AT_TOP 1 +#define REC_AT_BOTTOM 0 +#define CELL_VERTICAL_MARGIN (RULE_Y_OFFSET_TOP + RULE_Y_OFFSET_BOTTOM + 2) + +/*------------------------------------------------------------------------- +function: lm_allocate_rec_info +lmp: current lmp +realized_rows_array_len: number of realized rows in the realized rows array +-------------------------------------------------------------------------*/ +void +lm_allocate_rec_info( LM_DATA * lmp, int realized_rows_array_len ) +{ + int old_len = lmp->realized_rows_array_len; + int i; + + lmp->realized_rows_array_len = realized_rows_array_len; + + /* recs */ + if ( lmp->recs ) + { + lmp->recs = ( long * ) xi_tree_realloc( lmp->recs, sizeof( long ) * realized_rows_array_len ); + for ( i = old_len; i < realized_rows_array_len; ++i ) + lmp->recs[i] = 0L; + } + else + lmp->recs = ( long * ) xi_tree_malloc( sizeof( long ) * realized_rows_array_len, lmp ); + + /* pix_offsets */ + if ( lmp->pix_offsets ) + lmp->pix_offsets = ( int * ) xi_tree_realloc( lmp->pix_offsets, + sizeof( int ) * realized_rows_array_len ); + else + lmp->pix_offsets = ( int * ) xi_tree_malloc( sizeof( int ) * realized_rows_array_len, lmp ); + + /* pix_heights */ + if ( lmp->pix_heights ) + lmp->pix_heights = ( int * ) xi_tree_realloc( lmp->pix_heights, + sizeof( int ) * realized_rows_array_len ); + else + lmp->pix_heights = ( int * ) xi_tree_malloc( sizeof( int ) * realized_rows_array_len, lmp ); + + /* set_heights */ + if ( lmp->set_heights ) + lmp->set_heights = ( short * ) xi_tree_realloc( lmp->set_heights, + sizeof( int ) * realized_rows_array_len ); + else + lmp->set_heights = ( short * ) xi_tree_malloc( sizeof( int ) * realized_rows_array_len, lmp ); + + /* row_attribs */ + if ( lmp->row_attribs ) + { + lmp->row_attribs = ( unsigned long * ) xi_tree_realloc( lmp->row_attribs, + sizeof( unsigned long ) * realized_rows_array_len ); + for ( i = old_len; i < realized_rows_array_len; ++i ) + lmp->row_attribs[i] = LM_ROW_ATR_ENABLED; + } + else + lmp->row_attribs = ( unsigned long * ) xi_tree_malloc( sizeof( unsigned long ) * realized_rows_array_len, + lmp ); + + /* row_colors */ + if ( lmp->row_colors ) + { + lmp->row_colors = ( XinColor * ) xi_tree_realloc( lmp->row_colors, + sizeof( XinColor ) * realized_rows_array_len ); + for ( i = old_len; i < realized_rows_array_len; ++i ) + lmp->row_colors[i] = 0L; + } + else + lmp->row_colors = ( XinColor * ) xi_tree_malloc( sizeof( XinColor ) * realized_rows_array_len, + lmp ); + + /* cell_data */ + if ( lmp->cell_data ) + { + /* cell data destructor */ + for ( i = realized_rows_array_len; i < old_len; ++i ) + xi_tree_free( lmp->cell_data[i] ); + lmp->cell_data = ( LM_CELL_DATA ** ) xi_tree_realloc( lmp->cell_data, + sizeof( LM_CELL_DATA * ) * realized_rows_array_len ); + for ( i = old_len; i < realized_rows_array_len; ++i ) + lmp->cell_data[i] = ( LM_CELL_DATA * ) xi_tree_malloc( + ( lmp->nbr_columns + 1 ) * sizeof( LM_CELL_DATA ), lmp ); + } + else + lmp->cell_data = ( LM_CELL_DATA ** ) xi_tree_malloc( + sizeof( LM_CELL_DATA * ) * realized_rows_array_len, lmp ); +} + + +/*------------------------------------------------------------------------- +function: lm_create +win: window in which to put list +lm_def: list definition +parent: tree memory parent +-------------------------------------------------------------------------*/ +LM +lm_create( XinWindow win, LM_DEF * lm_def, void *parent ) +{ + LM_DATA *lmp; + int i, + font_height, + leading, + ascent, + descent, + mch, + realized_rows_array_len; + + lmp = LMP( xi_tree_malloc( sizeof( LM_DATA ), parent ) ); + lmp->focus_state = ( LM_FOCUS_STATE * ) xi_tree_malloc( sizeof( LM_FOCUS_STATE ), lmp ); + lmp->focus_state->where = LM_FOCUS_NOWHERE; + lmp->cid = lm_def->cid; + lmp->list_obj = lm_def->list_obj; + lmp->itf_obj = lm_def->itf_obj; + lmp->win = win; + lmp->font = lm_def->font; + lmp->is_list_font = lm_def->is_list_font; + lmp->back_color = lm_def->back_color; + lmp->enabled_color = lm_def->enabled_color; + lmp->disabled_color = lm_def->disabled_color; + lmp->disabled_back_color = lm_def->disabled_back_color; + lmp->active_color = lm_def->active_color; + lmp->active_back_color = lm_def->active_back_color; + lmp->white_space_color = lm_def->white_space_color; + lmp->rule_color = lm_def->rule_color; + lmp->attrib = lm_def->attrib; + lmp->lm_cb = lm_def->lm_cb; + lmp->no_heading = lm_def->no_heading; + lmp->sizable_columns = lm_def->sizable_columns; + lmp->movable_columns = lm_def->movable_columns; + lmp->fixed_columns = lm_def->fixed_columns; + lmp->resize_with_window = lm_def->resize_with_window; + lmp->horz_sync_list = lm_def->horz_sync_list; + lmp->vert_sync_list = lm_def->vert_sync_list; + lmp->row_focus_border = lm_def->row_focus_border; + lmp->row_focus_border_color = lm_def->row_focus_border_color; + lmp->single_select = lm_def->single_select; + lmp->pixel_width = lm_def->pixel_width; + lmp->pixel_height = lm_def->pixel_height; +#if XIWS == XIWS_WM + lmp->min_cell_height = 0; + lmp->min_heading_height = lm_def->min_heading_height; +#else + lmp->min_cell_height = lm_def->min_cell_height; + lmp->min_heading_height = lm_def->min_heading_height; +#endif + lmp->no_horz_lines = lm_def->no_horz_lines; + lmp->no_vert_lines = lm_def->no_vert_lines; + lmp->first_vis = lmp->fixed_columns; + lmp->drop_and_delete = lm_def->drop_and_delete; + lmp->select_cells = lm_def->select_cells; + lmp->get_all_records = lm_def->get_all_records; + lmp->retain_back_color_on_select = lm_def->retain_back_color_on_select; + lmp->drag_and_drop_rows = lm_def->drag_and_drop_rows; + lmp->drag_rows_autoscroll = lm_def->drag_rows_autoscroll; + lmp->button_on_cell_focus = lm_def->button_on_cell_focus; + lmp->position_by_typing_cid = lm_def->position_by_typing_cid; + lmp->max_lines_in_cell = lm_def->max_lines_in_cell; + if ( !lmp->max_lines_in_cell ) + lmp->max_lines_in_cell = + ( int ) xi_get_pref( XI_PREF_DEFAULT_MAX_LINES_IN_CELL ); + XinWindowFontMap( win, lm_def->font ); + XinFontMetricsGet( lm_def->font, &leading, &ascent, &descent ); + lmp->cur_font = lm_def->font; + lmp->leading = leading; + lmp->ascent = ascent; + lmp->descent = descent; + font_height = lmp->ascent + lmp->leading + lmp->descent; + + /* we add two to the following line so that there is room in the cell for the + * row focus border */ +#if XIWS == XIWS_WM + lmp->pix_cell_height = font_height; +#else + lmp->pix_cell_height = font_height + CELL_VERTICAL_MARGIN; +#endif +#if XIWS == XIWS_WM + mch = 8; +#else + mch = lm_def->min_cell_height; +#endif + lmp->pix_cell_height = max( lmp->pix_cell_height, mch ); + lmp->pix_row_spacing = lmp->pix_cell_height + RULE_WIDTH_H; + lmp->pix_top = lm_def->pnt.v; +#if XIWS == XIWS_WM + lmp->pix_hdr_bottom = lm_def->pnt.v + lmp->leading + lmp->ascent + + lmp->descent + BORDER_WIDTH + + RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP; + lmp->pix_hdr_bottom = max( lmp->pix_hdr_bottom, ( lm_def->pnt.v + + lmp->min_heading_height - BORDER_WIDTH ) ); +#else + lmp->pix_hdr_bottom = lm_def->pnt.v + lmp->leading + lmp->ascent + + lmp->descent + BORDER_WIDTH + RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP + 1; + lmp->pix_hdr_bottom = max( lmp->pix_hdr_bottom, ( lm_def->pnt.v + lmp->min_heading_height ) ); +#endif + if ( lmp->no_heading ) + lmp->pix_row1_top = lm_def->pnt.v + BORDER_WIDTH; + else + lmp->pix_row1_top = lmp->pix_hdr_bottom + BORDER_WIDTH; + lmp->pix_char_width = lm_def->pix_char_width; + lmp->nbr_columns = 0; + lmp->lm_column_data = NULL; + + /* compute number of rows */ + lmp->nbr_rows = lm_def->nbr_rows; + if ( lm_def->nbr_rows ) + lmp->nbr_rows = lm_def->nbr_rows; + else + lmp->nbr_rows = ( lm_def->pixel_height - ( lmp->pix_row1_top - lm_def->pnt.v ) + - BORDER_WIDTH ) / lmp->pix_row_spacing; + if ( lm_def->one_row_list ) + { + lmp->nbr_rows = 1; + lm_def->resize_with_window = FALSE; + } + + lmp->rct.left = lm_def->pnt.h; + lmp->rct.top = lm_def->pnt.v; +#if XIWS != XIWS_WM + lmp->rct.right = lm_def->pnt.h + 2 * BORDER_WIDTH; + if ( lm_def->resize_with_window ) + lmp->rct.bottom = lm_def->pnt.v + lm_def->pixel_height; + else + lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing + + ( BORDER_WIDTH - RULE_WIDTH_H ); +#else + lmp->rct.right = lm_def->pnt.h + BORDER_WIDTH; + if ( lm_def->resize_with_window ) + lmp->rct.bottom = lm_def->pnt.v + lm_def->pixel_height; + else + lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing + + BORDER_WIDTH; +#endif + lmp->vir_left = lmp->rct.left + BORDER_WIDTH; + lmp->vir_right = lmp->vir_left + lmp->pixel_width; + + realized_rows_array_len = lm_def->realized_rows_array_len; + if ( !realized_rows_array_len ) + realized_rows_array_len = lmp->nbr_rows + 1; + lm_allocate_rec_info( lmp, realized_rows_array_len ); + + /* calculate mathematical list rectangle */ + lmp->mlr.top = lmp->pix_row1_top; +#if XIWS != XIWS_WM + lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH; + lmp->mlr.left = lmp->rct.left + BORDER_WIDTH; + lmp->mlr.right = lmp->rct.right - BORDER_WIDTH; +#else + if ( lmp->pixel_width ) + lmp->mlr.bottom = lmp->rct.bottom; + else + lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH; + lmp->mlr.left = lmp->rct.left; + lmp->mlr.right = lmp->rct.right; +#endif + lmp->mlr_height = lmp->mlr.bottom - lmp->mlr.top; + + for ( i = 0; i < lmp->realized_rows_array_len; ++i ) + { + lmp->cell_data[i] = ( LM_CELL_DATA * ) xi_tree_malloc( + lmp->nbr_columns * sizeof( LM_CELL_DATA ), lmp ); + lmp->row_attribs[i] = LM_ROW_ATR_ENABLED; + } + + return ( ( LM ) ( long ) lmp ); +} + + +/*------------------------------------------------------------------------- +function: lm_do_rec_event +lmp: current lmp +row: row to do event on +type: XI_EVENT_TYPE +notes: In this case, row is not really a row. It is an index into the + realized rows array. +-------------------------------------------------------------------------*/ +void +lm_do_rec_event( LM_DATA * lmp, int row, XI_EVENT_TYPE type ) +{ + LM_CELL_DATA *cell_data; + int i; + + if ( type == XIE_REC_FREE ) + { + if ( lmp->recs[row] != lm_focus_rec_get( lmp ) ) + do_lm_cb( ( LM ) lmp, LM_CB_REC_FREE, row, 0, NULL, NULL, 0 ); + cell_data = lmp->cell_data[row]; + /* cell_data_destruct */ + for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data ) + { + if ( cell_data->font ) + XinFontDestroy( cell_data->font ); + xi_bitmap_destroy( cell_data->bitmap ); + xi_bitmap_destroy( cell_data->button_bitmap ); + if ( cell_data->xi_text ) + xi_text_destruct( cell_data->xi_text ); + memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) ); + } + lmp->recs[row] = 0L; + /* we technically do not need to do the following lines. it just keeps the + * data structures clean. */ + lmp->pix_heights[row] = 0; + lmp->set_heights[row] = FALSE; + lmp->pix_offsets[row] = 0; + lmp->row_attribs[row] = 0L; + lmp->row_colors[row] = 0L; + } + /* cell_data_construct */ + if ( type == XIE_REC_ALLOCATE ) + { + do_lm_cb( ( LM ) lmp, LM_CB_REC_ALLOCATE, row, 0, NULL, NULL, 0 ); + cell_data = lmp->cell_data[row]; + for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data ) + { + memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) ); + lm_xi_text_construct( lmp, row, i ); + } + } +} + + +/*------------------------------------------------------------------------- +function: lm_row_copy +lmp: current lmp +source_row: row from which to copy +dest_row: destination row +-------------------------------------------------------------------------*/ +void +lm_row_copy( LM_DATA * lmp, int source_row, int dest_row ) +{ + int idx; + LM_CELL_DATA *dest_cell_data, + *source_cell_data; + + lmp->recs[dest_row] = lmp->recs[source_row]; + lmp->pix_heights[dest_row] = lmp->pix_heights[source_row]; + lmp->set_heights[dest_row] = lmp->set_heights[source_row]; + lmp->pix_offsets[dest_row] = lmp->pix_offsets[source_row]; + lmp->row_attribs[dest_row] = lmp->row_attribs[source_row]; + lmp->row_colors[dest_row] = lmp->row_colors[source_row]; + for ( idx = 0, + dest_cell_data = lmp->cell_data[dest_row], + source_cell_data = lmp->cell_data[source_row]; + idx < lmp->nbr_columns; + ++idx, + ++dest_cell_data, + ++source_cell_data ) + { + *dest_cell_data = *source_cell_data; + } +} + + +/*------------------------------------------------------------------------- +function: init_row +lmp: current lmp +row: row to init +-------------------------------------------------------------------------*/ +static void +init_row( LM_DATA * lmp, int row ) +{ + int idx; + LM_CELL_DATA *cell_data; + + lmp->recs[row] = 0L; + lmp->pix_heights[row] = 0; + lmp->set_heights[row] = 0; + lmp->pix_offsets[row] = 0; + lmp->row_attribs[row] = LM_ROW_ATR_ENABLED; + lmp->row_colors[row] = 0; + for ( idx = 0, + cell_data = lmp->cell_data[row]; + idx < lmp->nbr_columns; + ++idx, + ++cell_data ) + { + memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) ); + } +} + + +/*------------------------------------------------------------------------- +function: make_rec_available +lmp: current lmp +top: record to become available is at the top of the realized_row array, + else the record to become available is at the bottom of the realized + row array. +allocate_rec: if TRUE, then send XIE_REC_ALLOCATE event +notes: if, in order to get a record at the bottom of the realized row array, + we must discard a record at the beginning of the rrr array, then + we must change lmp->rrr_offset. + whenever we make a record be available, make sure that we free + fonts in cell_data. + Also, clear cell_data. +-------------------------------------------------------------------------*/ +static void +make_rec_available( LM_DATA * lmp, BOOLEAN top, BOOLEAN allocate_rec, + BOOLEAN doing_scroll_first ) +{ + int cnt; + + if ( top ) + { + int idx; + + if ( !lmp->get_all_records ) + { + int nbr_to_free; + + nbr_to_free = lmp->nbr_realized_rows - ( lmp->last_fully_vis + 2 ); + if ( nbr_to_free > 0 ) + { + /* free as many records at the end of the list as possible */ + for ( idx = lmp->last_fully_vis + 2; idx < lmp->nbr_realized_rows; + ++idx ) + lm_do_rec_event( lmp, idx, XIE_REC_FREE ); + lmp->nbr_realized_rows -= nbr_to_free; + } + + if ( lmp->nbr_realized_rows >= lmp->realized_rows_array_len ) + lm_allocate_rec_info( lmp, lmp->realized_rows_array_len + 1 ); + + /* copy all the records, making room at the beginning of the realized_row + * array */ + ++lmp->nbr_realized_rows; + for ( idx = lmp->nbr_realized_rows - 1; + idx > 0; --idx ) + lm_row_copy( lmp, idx - 1, idx ); + lm_adjust_rows( lmp, 1 ); + init_row( lmp, 0 ); + if ( allocate_rec ) + lm_do_rec_event( lmp, 0, XIE_REC_ALLOCATE ); + return; + } + } + else + { + if ( !lmp->get_all_records || doing_scroll_first ) + { + /* free as many records at the beginning of the list as possible */ + cnt = lmp->first_fully_vis - 2; + if ( cnt > 0 ) + { + int idx, + jidx; + + for ( idx = 0; idx < cnt; ++idx ) + { + lmp->rrr_offset += lmp->pix_heights[idx]; + lm_do_rec_event( lmp, idx, XIE_REC_FREE ); + } + + lmp->nbr_realized_rows -= cnt; + + /* copy all the records, making room at the end of the realized row + * array */ + for ( idx = cnt, jidx = 0; + jidx < lmp->nbr_realized_rows; + ++idx, ++jidx ) + lm_row_copy( lmp, idx, idx - cnt ); + lm_adjust_rows( lmp, -cnt ); + } + if ( lmp->nbr_realized_rows >= lmp->realized_rows_array_len ) + lm_allocate_rec_info( lmp, lmp->realized_rows_array_len + 1 ); + ++lmp->nbr_realized_rows; + init_row( lmp, lmp->nbr_realized_rows - 1 ); + if ( allocate_rec ) + lm_do_rec_event( lmp, lmp->nbr_realized_rows - 1, XIE_REC_ALLOCATE ); + return; + } + } +} + + +/*------------------------------------------------------------------------- +function: get_next_rec +lmp: current lmp +returns: TRUE if next record was available + FALSE if not +-------------------------------------------------------------------------*/ +static BOOLEAN +get_next_rec( LM_DATA * lmp, BOOLEAN doing_scroll_first ) +{ + int idx, + row_height; + + make_rec_available( lmp, REC_AT_BOTTOM, TRUE, doing_scroll_first ); + idx = lmp->nbr_realized_rows - 1; + if ( do_lm_cb_get( ( LM ) lmp, LM_CB_GET_NEXT, + &lmp->recs[idx - 1], &lmp->recs[idx], 0, &lmp->row_colors[idx], + &lmp->row_attribs[idx], &row_height ) ) + { + lm_do_rec_event( lmp, lmp->nbr_realized_rows - 1, XIE_REC_FREE ); + --lmp->nbr_realized_rows; + return FALSE; + } + + if ( row_height ) + { + lmp->pix_heights[idx] = row_height; + lmp->set_heights[idx] = TRUE; + } + else + { + lmp->pix_heights[idx] = 0; + lmp->set_heights[idx] = FALSE; + } + + lm_invalidate_rows_internal( ( LM ) lmp, idx, idx, FALSE, -1, TRUE ); + + return TRUE; +} + + +/*------------------------------------------------------------------------- +function: get_previous_rec +lmp: current lmp +returns: TRUE if previous record was available + FALSE if not +-------------------------------------------------------------------------*/ +static BOOLEAN +get_previous_rec( LM_DATA * lmp ) +{ + int row_height, + cnt; + + make_rec_available( lmp, REC_AT_TOP, TRUE, FALSE ); + if ( do_lm_cb_get( ( LM ) lmp, LM_CB_GET_PREV, + &lmp->recs[1], &lmp->recs[0], 0, &lmp->row_colors[0], + &lmp->row_attribs[0], &row_height ) ) + { + lm_do_rec_event( lmp, 0, XIE_REC_FREE ); + for ( cnt = 0; cnt < lmp->nbr_realized_rows - 1; ++cnt ) + lm_row_copy( lmp, cnt + 1, cnt ); + lm_adjust_rows( lmp, -1 ); + --lmp->nbr_realized_rows; + return FALSE; + } + if ( row_height ) + { + lmp->pix_heights[0] = row_height; + lmp->set_heights[0] = TRUE; + } + else + { + lmp->pix_heights[0] = 0; + lmp->set_heights[0] = FALSE; + } + lm_invalidate_rows_internal( ( LM ) lmp, 0, 0, FALSE, -1, TRUE ); + return TRUE; +} + + +/*------------------------------------------------------------------------- +function: calculate_cell_height +lmp: current lmp +row: row number of cell to calculate +column: column number of cell to calculate +returns: height of cell in pixels +notes: this function does not need to take into consideration the + variable fixed_row_height. This function is only used by + lm_calculate_row_height, and will only be called if + fixed_row_height is false. +-------------------------------------------------------------------------*/ +static int +calculate_cell_height( LM_DATA * lmp, int row, int column ) +{ + int pix_height; /* pix_height does include the width of the + * rules */ + int nbr_lines; + LM_CELL_DATA *cell_data; + LM_COLUMN_DATA *lm_column_data; + + cell_data = &lmp->cell_data[row][column]; + lm_column_data = lmp->lm_column_data[column]; + if ( !cell_data->font_height ) + { + XinFont *font; + int leading, + ascent, + descent, + char_width; + + if ( lm_column_data->wrap_text && !cell_data->valid_data ) + do_lm_cb_text( lmp, row, column, TRUE ); + if ( cell_data->font ) + font = cell_data->font; + else + font = lmp->font; + xi_get_font_metrics_font( font, &leading, &ascent, &descent, &char_width ); + cell_data->font_height = leading + ascent + descent; + } + if ( lm_column_data->wrap_text ) + { + int pix_spacing; + BOOLEAN is_editing; + int ip1, + ip2, + start_ip; + + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, column, TRUE ); + is_editing = xi_text_editing_is( cell_data->xi_text ); + if ( is_editing ) + xi_text_selection_get_internal( cell_data->xi_text, &ip1, &ip2, &start_ip ); + xi_text_initialized_set( cell_data->xi_text, FALSE ); + pix_spacing = lm_column_data->pix_width - + ( cell_data->button ? lmp->pix_row_spacing : 0 ); + xi_text_pix_width_set( cell_data->xi_text, pix_spacing ); + if ( is_editing ) + xi_text_selection_set_internal( cell_data->xi_text, ip1, ip2, start_ip, FALSE, FALSE ); + nbr_lines = min( xi_text_nbr_lines_get( cell_data->xi_text ), lmp->max_lines_in_cell ); + } + else + nbr_lines = 1; +#if XIWS != XIWS_WM + pix_height = nbr_lines * cell_data->font_height + CELL_VERTICAL_MARGIN + + RULE_WIDTH_H; +#else + pix_height = nbr_lines * cell_data->font_height; +#endif + + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VERTICALLY_SCROLLED ) + { + int focus_row, + focus_column; + BOOLEAN v_scrolled; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + if ( focus_column == column && lmp->recs[row] == lmp->focus_state->focus_rec ) + pix_height = lmp->focus_state->focus_rec_height; + } + + + pix_height = max( pix_height, lmp->pix_row_spacing ); + return pix_height; +} + + +/*------------------------------------------------------------------------- +function: lm_calculate_row_height +lmp: current lmp +row: row number to calculate +returns: height of row in pixels +notes: if fixed_row_height is TRUE, then the calculation is easy. + if fixed_row_height is FALSE, then the calculation must take + word wrap into consideration, etc. + row height includes the height of the horizontal rule below + the row. +-------------------------------------------------------------------------*/ +int +lm_calculate_row_height( LM_DATA * lmp, int row ) +{ + int pix_height; + + if ( lmp->fixed_row_height ) + pix_height = lmp->pix_row_spacing; + else if ( lmp->set_heights[row] ) + pix_height = lmp->pix_heights[row]; + else + { + int cnt; + int cell_height; + + pix_height = 0; + for ( cnt = 0; cnt < lmp->nbr_columns; ++cnt ) + { + cell_height = calculate_cell_height( lmp, row, cnt ); + pix_height = max( pix_height, cell_height ); + } + } + if ( pix_height > lmp->mlr_height ) + pix_height = lmp->mlr_height; + return pix_height; +} + + +/*------------------------------------------------------------------------- +function: calculate_visibles +lmp: current lmp +process: calculates lmp->first_fully_vis + calculates lmp->last_fully_vis +-------------------------------------------------------------------------*/ +void +calculate_visibles( LM_DATA * lmp ) +{ + int i, + idx; + int *pix_offsetsp; + int *pix_heightsp; + BOOLEAN have_first; + + have_first = FALSE; + lmp->first_fully_vis = 0; + lmp->last_fully_vis = 0; + for ( i = 0, + pix_offsetsp = &lmp->pix_offsets[i], + pix_heightsp = &lmp->pix_heights[i]; + i < lmp->nbr_realized_rows; + ++i, ++pix_offsetsp, ++pix_heightsp ) + { + if ( !have_first && *pix_offsetsp >= ( -lmp->rrr_offset ) ) + { + have_first = TRUE; + lmp->first_fully_vis = i; + } + /* should be <, because we are dealing with mathematical rects, but we + * don't care if the rule is not on the list. pix_offsetp + *pix_heightsp + * is the mathematical rect of the row, in rrr terms. lmp->rrr_offset + + * lmp->mlr_height is the mathematical rect of the list, in rrr terms. */ +#if XIWS == XIWS_WM + if ( *pix_offsetsp + *pix_heightsp + lmp->rrr_offset <= lmp->mlr_height ) + lmp->last_fully_vis = i; +#else + if ( *pix_offsetsp + *pix_heightsp - 1 + lmp->rrr_offset <= lmp->mlr_height ) + lmp->last_fully_vis = i; +#endif + } + if ( lmp->nbr_realized_rows ) + { + idx = lmp->nbr_realized_rows - 1; + lmp->rrr_bottom = lmp->pix_offsets[idx] + lmp->pix_heights[idx]; + } + else + lmp->rrr_bottom = 0; +} + + +/*------------------------------------------------------------------------- +function: calculate_pix_offsets +lmp: current lmp +process: calculates the lmp->pix_offsets array + calculates lmp->first_fully_vis + calculates lmp->last_fully_vis +-------------------------------------------------------------------------*/ +void +calculate_pix_offsets( LM_DATA * lmp, BOOLEAN draw_changes ) +{ + int i, + cur_pix, + idx; + int *pix_offsetsp; + int *pix_heightsp; + BOOLEAN have_first; + + cur_pix = 0; + have_first = FALSE; + for ( i = 0, + pix_offsetsp = &lmp->pix_offsets[i], + pix_heightsp = &lmp->pix_heights[i]; + i < lmp->nbr_realized_rows; + ++i, ++pix_offsetsp, ++pix_heightsp ) + { + int new_height; + + new_height = lm_calculate_row_height( lmp, i ); + if ( draw_changes && + ( *pix_offsetsp != cur_pix || *pix_heightsp != new_height ) ) + { + XinRect rect; + + lm_get_row_rect( &rect, ( LM ) lmp, i ); + lm_invalidate_rect( lmp, &rect, FALSE ); + rect.top = cur_pix; + rect.bottom = cur_pix + new_height; + lm_invalidate_rect( lmp, &rect, FALSE ); + } + *pix_offsetsp = cur_pix; + *pix_heightsp = new_height; + if ( !have_first && cur_pix >= ( -lmp->rrr_offset ) ) + { + have_first = TRUE; + lmp->first_fully_vis = i; + } + cur_pix += new_height; + /* should be <=, because we are dealing with mathematical rects, but we + * don't care if the rule is not on the list. pix_offsetp + *pix_heightsp + * is the mathematical rect of the row, in rrr terms. lmp->rrr_offset + + * lmp->mlr_height is the mathematical rect of the list, in rrr terms. */ +#if XIWS == XIWS_WM + if ( cur_pix + lmp->rrr_offset <= lmp->mlr_height ) + lmp->last_fully_vis = i; +#else + if ( cur_pix - 1 + lmp->rrr_offset <= lmp->mlr_height ) + lmp->last_fully_vis = i; +#endif + } + if ( lmp->nbr_realized_rows ) + { + idx = lmp->nbr_realized_rows - 1; + lmp->rrr_bottom = lmp->pix_offsets[idx] + lmp->pix_heights[idx]; + } + else + lmp->rrr_bottom = 0; +} + + +/*------------------------------------------------------------------------- +function: make_rrr_room_pix +lmp: current lmp +pixels: number of additional pixels desired in realized row rect + pixels may be negative, in which case, the desired pixels + are above the realized row rect + pixels may be positive, in which case, the desired pixels + are below the realized row rect +returns: recs read +-------------------------------------------------------------------------*/ +int +lm_make_rrr_room_pix( LM_DATA * lmp, int pixels, BOOLEAN do_redraw ) +{ + int recs_read = 0; + int idx; + + if ( lmp->nbr_realized_rows == 0 || lmp->nbr_columns == 0 ) + { + lmp->rrr_bottom = 0; + calculate_pix_offsets( lmp, FALSE ); + return 0; + } + + idx = lmp->nbr_realized_rows - 1; + lmp->rrr_bottom = lmp->pix_offsets[idx] + lmp->pix_heights[idx]; + + if ( pixels == 0 ) + return recs_read; + + if ( pixels < 0 ) + { + while ( TRUE ) + { + if ( pixels >= lmp->rrr_offset ) + return recs_read; + if ( get_previous_rec( lmp ) ) + { + int row_height; + + row_height = lm_calculate_row_height( lmp, 0 ); + lmp->rrr_offset -= row_height; + calculate_pix_offsets( lmp, do_redraw ); + calculate_visibles( lmp ); + ++recs_read; + } + else + return recs_read; + } + } + else + { + while ( TRUE ) + { + if ( lmp->rrr_bottom - lmp->mlr_height + lmp->rrr_offset >= pixels ) + return recs_read; + if ( lmp->get_all_records ) + return recs_read; + if ( get_next_rec( lmp, FALSE ) ) + { + calculate_pix_offsets( lmp, do_redraw ); + calculate_visibles( lmp ); + ++recs_read; + } + else + return recs_read; + } + } +} + + +/*------------------------------------------------------------------------- +function: make_rrr_room_rows +lmp: current lmp +nbr_rows: nbr of rows to scroll +returns: pixels to scroll +-------------------------------------------------------------------------*/ +static int +make_rrr_room_rows( LM_DATA * lmp, int *rows, BOOLEAN do_redraw ) +{ + int nbr_rows = *rows; + + if ( nbr_rows < 0 ) + { + /* convert nbr_rows to positive, for ease of programming */ + nbr_rows = -nbr_rows; + while ( TRUE ) + { + if ( !nbr_rows ) + { + *rows = 0; + return 0; + } + if ( lmp->first_fully_vis - nbr_rows >= 0 ) + { + int pixels; + + pixels = -( lmp->pix_offsets[lmp->first_fully_vis] - + lmp->pix_offsets[lmp->first_fully_vis - nbr_rows] ); + lmp->update_rows_at_top = nbr_rows; + *rows = nbr_rows; + return pixels; + } + else + { + if ( !lmp->get_all_records && get_previous_rec( lmp ) ) + { + lmp->pix_heights[0] = lm_calculate_row_height( lmp, 0 ); + lmp->rrr_offset -= lmp->pix_heights[0]; + calculate_pix_offsets( lmp, do_redraw ); + } + else + { + calculate_pix_offsets( lmp, do_redraw ); + nbr_rows = lmp->first_fully_vis; + } + } + } + } + else + { + BOOLEAN get_next_accepted = TRUE; + int pixels; + + pixels = lmp->pix_offsets[lmp->first_fully_vis + nbr_rows] - + lmp->pix_offsets[lmp->first_fully_vis]; + while ( TRUE ) + { + int delta_avail; + + if ( !nbr_rows ) + { + *rows = 0; + return 0; + } + /* if get_all_records is true, then we never need to get more records if + * there is a row beyond the last partially visible row, then we don't + * need to get more records if a get next has been refused, then we have + * all the records that we are going to get */ + if ( lmp->get_all_records || + lmp->last_fully_vis + 1 + nbr_rows < lmp->nbr_realized_rows || + !get_next_accepted ) + { + delta_avail = lmp->pix_offsets[lmp->nbr_realized_rows - 1] + + lmp->pix_heights[lmp->nbr_realized_rows - 1] + + lmp->rrr_offset - lmp->mlr_height; + if ( lmp->get_all_records || pixels <= delta_avail || !get_next_accepted ) + { + int nrows, + cnt, + pcnt; + + for ( nrows = 0, cnt = lmp->last_fully_vis + 1, pcnt = 0; + pcnt < pixels && cnt < lmp->nbr_realized_rows; + ++nrows, ++cnt, pcnt += lmp->pix_heights[cnt] ) + ; + lmp->update_rows_at_bottom = nrows; + *rows = nbr_rows; + return pixels; + } + } + if ( !lmp->get_all_records + && ( get_next_accepted = get_next_rec( lmp, FALSE ) ) != 0 ) + calculate_pix_offsets( lmp, do_redraw ); + else + { + calculate_pix_offsets( lmp, do_redraw ); + nbr_rows = lmp->nbr_realized_rows - 1 - lmp->last_fully_vis; + } + } + } +} + +static int +make_room_rows( LM_DATA * lm_data, int rows, BOOLEAN do_draw ) +{ + return make_rrr_room_rows( lm_data, &rows, do_draw ); +} + +/*------------------------------------------------------------------------- +function: do_scroll_bar +itf: current itf +listdata: list_data +list: list +-------------------------------------------------------------------------*/ +void +do_scroll_bar( XI_LIST_DATA * listdata ) +{ + LM_DATA *lmp; + + if ( listdata->scroll_bar ) + { + lmp = ( LM_DATA * ) listdata->lm; + if ( lmp->get_all_records ) + { + int top, + prop; + + if ( lmp->rrr_offset == 0 && lmp->rrr_bottom < lmp->mlr_height ) + { + top = 0; + prop = 100; + } + else + { + top = ( int ) ( -lmp->rrr_offset * 100L / lmp->rrr_bottom ); + if ( lmp->mlr_height - lmp->rrr_offset >= lmp->rrr_bottom - 1 ) + prop = 100 - top; + else + prop = ( int ) ( lmp->mlr_height * 100L / lmp->rrr_bottom ); + } + prop = max( 0, min( 100, prop ) ); + XinScrollBarSet( listdata->sb_win, XinScrollBarTypeEither, 0, 100, + prop, top ); + } + else + { + int percent1 = 0; + int percent2 = 100; + int prop = 100; + + if ( lmp->nbr_realized_rows > 1 ) + { + do_lm_cb( listdata->lm, LM_CB_GET_PERCENT, lmp->first_fully_vis, + 0, NULL, &percent1, 0 ); + do_lm_cb( listdata->lm, LM_CB_GET_PERCENT, lmp->last_fully_vis, + 0, NULL, &percent2, 0 ); + prop = min(100, max( 1, ( percent2 - percent1 ) ) ); +#if XIWS == XIWS_WXGTK + const int act_pos = XinScrollBarPositionGet( listdata->sb_win, XinScrollBarTypeEither ); + if (act_pos >= percent1 && act_pos <= percent2) + percent1 = -1; +#endif + } +#if XIWS != XIWS_WXGTK + else + prop = min(100, max( 1, ( percent2 - percent1 ) ) ); +#endif + XinScrollBarSet( listdata->sb_win, XinScrollBarTypeEither, 0, + 100, prop, percent1 ); + } + } +} + +/*------------------------------------------------------------------------- +function: lm_remove_all_rows +lm: current lm +-------------------------------------------------------------------------*/ + +void +lm_remove_all_rows( LM_DATA * lmp, BOOLEAN delete_focus ) +{ + int i; + LM_CB_DATA lm_cb_data; + + if ( lm_focus_rec_get( lmp ) && delete_focus ) + { + int idx; + BOOLEAN found = FALSE; + + for ( idx = 0; idx < lmp->nbr_realized_rows; ++idx ) + { + if ( lm_focus_rec_get( lmp ) == lmp->recs[idx] ) + { + found = TRUE; + break; + } + } + if ( !found ) + { + lm_cb_data.lm = ( LM ) lmp; + lm_cb_data.cb_type = LM_CB_REC_FREE; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.v.rec_free.record = lm_focus_rec_get( lmp ); + ( *lmp->lm_cb ) ( &lm_cb_data ); + } + } + + for ( i = 0; i < lmp->nbr_realized_rows; ++i ) + lm_do_rec_event( lmp, i, XIE_REC_FREE ); + + lmp->nbr_realized_rows = 0; + lmp->rrr_bottom = 0; + lmp->rrr_offset = 0; +} + + +BOOLEAN +lm_row_has_focus( LM_DATA * lmp, int row, BOOLEAN is_vert_scrolled ) +{ + XI_ITF_DATA *itf; + XI_OBJ *focus_obj; + XI_CELL_DATA *cd; + +#if 0 + if ( lmp->txt_is_invisible && !lmp->horizontally_scrolling_list ) + return FALSE; +#endif + itf = lmp->itf_obj->v.itf; + focus_obj = itf->focus_obj; + if ( focus_obj != NULL && focus_obj->parent == lmp->list_obj && + focus_obj->type == XIT_CELL ) + { + cd = &focus_obj->v.cell; + return ( cd->row == row && cd->is_vert_scrolled == is_vert_scrolled ); + } + return FALSE; +} + + +/*------------------------------------------------------------------------- +function: fill_previous +returns: # of records read +-------------------------------------------------------------------------*/ +static int +fill_previous( LM_DATA * lmp ) +{ + int *pix_heights, + *pix_offsets; + int offset, + height; + int i; + int result = 0; + + while ( TRUE ) + { + + if ( !get_previous_rec( lmp ) ) + break; + result++; + /* recalculate the heights and offsets of every row */ + lmp->pix_heights[0] = lm_calculate_row_height( lmp, 0 ); + offset = 0; + for ( i = 0, pix_heights = &lmp->pix_heights[0], + pix_offsets = &lmp->pix_offsets[0]; + i < lmp->nbr_realized_rows; + ++i, ++pix_heights, ++pix_offsets ) + { + *pix_offsets = offset; + offset += *pix_heights; + } + + calculate_visibles( lmp ); + + /* if we finally have enough rows to display the entire list + * + * note: we subtract 1 from the space necessary because it is not necessary to + * create space for the pixel at the bottom of the last row. */ + height = lmp->pix_heights[lmp->nbr_realized_rows - 1]; + if ( !height ) + height = lmp->pix_row_spacing; + if ( !lmp->get_all_records && + ( lmp->pix_offsets[lmp->nbr_realized_rows - 1] + + height - 1 + >= lmp->mlr_height ) ) + break; + } + + calculate_pix_offsets( lmp, FALSE ); + + lmp->rrr_bottom = lmp->pix_offsets[lmp->nbr_realized_rows - 1] + + lmp->pix_heights[lmp->nbr_realized_rows - 1]; + /* subtract 1 from rrr_bottom because of the pixel at the bottom of the last + * row. */ + lmp->rrr_offset = lmp->mlr_height - ( lmp->rrr_bottom - 1 ); + lmp->rrr_offset = min( 0, lmp->rrr_offset ); + + /* although we have adjusted pix_offsets, and pix_heights, it is still + * necessary to calculate the first and last fully visible rows */ + calculate_visibles( lmp ); + + /* if the page down does not make the first row editable, then scroll the + * exact amount to make it editable */ + if ( -lmp->rrr_offset != + lmp->pix_offsets[lmp->first_fully_vis] ) + { + lmp->rrr_offset = -lmp->pix_offsets[lmp->first_fully_vis]; + calculate_visibles( lmp ); + } + return result; +} + +/*-------------------------------------------------------------------------*/ +/* data structure for passing around lm_scroll functions */ +/*-------------------------------------------------------------------------*/ + +typedef struct +{ + int nbr_lines; + int percent; + long rec; + BOOLEAN have_rec; + XinColor color; + unsigned long attrib; + int row_height_arg; + int scroll_type; + int pix_overlap; + int nbr_pixels; + XinRect focus_cell_rct; + BOOLEAN have_pixels; + BOOLEAN list_had_focus; + BOOLEAN is_first_or_last; + int focus_row; + int focus_column; + BOOLEAN v_scrolled; + int pixels_scrolled; +} lm_scroll_data; + +/*-------------------------------------------------------------------------*/ +/* lm_scroll_data_construct */ +/*-------------------------------------------------------------------------*/ + +static void +lm_scroll_data_construct( LM_DATA * lmp, lm_scroll_data * data, + LM_SCROLL_ARG * arg ) +{ + int pref_overlap; + + data->nbr_lines = arg->nbr_lines; + data->percent = arg->percent; + data->rec = arg->rec; + data->have_rec = arg->have_rec; + data->color = arg->color; + data->attrib = arg->attrib; + data->row_height_arg = arg->row_height; + data->have_pixels = FALSE; + data->list_had_focus = FALSE; + data->is_first_or_last = FALSE; + if ( arg->nbr_lines == XI_SCROLL_FIRST && arg->percent == 100 ) + data->nbr_lines = XI_SCROLL_LAST; + if ( !lmp->nbr_realized_rows ) + data->nbr_lines = XI_SCROLL_FIRST; + if ( arg->have_rec ) + { + if ( arg->rec_at_top ) + data->nbr_lines = XI_SCROLL_FIRST; + else + data->nbr_lines = XI_SCROLL_LAST; + } + data->scroll_type = data->nbr_lines; + pref_overlap = ( int ) xi_get_pref( XI_PREF_OVERLAP ); + data->pix_overlap = pref_overlap * lmp->pix_row_spacing; + data->pixels_scrolled = 0; +} + +/*-------------------------------------------------------------------------*/ +/* lm_scroll_remove focus */ +/*-------------------------------------------------------------------------*/ + +static BOOLEAN +lm_scroll_remove_focus( LM_DATA * lmp, lm_scroll_data * data, + XI_OBJ * old_focus_obj ) +{ + /* remove the focus from the list being scrolled */ + if ( lm_focus_list_has( lmp ) ) + { + data->list_had_focus = TRUE; + lm_focus_cell_get( lmp, &data->focus_row, &data->focus_column, + &data->v_scrolled ); + if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + { + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + { + lm_focus_cell_invis_make( lmp ); + switch ( data->nbr_lines ) + { + case XI_SCROLL_FIRST: + lm_focus_rec_is_above_set( lmp, FALSE ); + case XI_SCROLL_LAST: + lm_focus_rec_is_above_set( lmp, TRUE ); + break; + case XI_SCROLL_PGUP: + lm_focus_rec_is_above_set( lmp, FALSE ); + break; + case XI_SCROLL_PGDOWN: + lm_focus_rec_is_above_set( lmp, TRUE ); + break; + default: + lm_focus_rec_is_above_set( lmp, ( BOOLEAN ) ( data->nbr_lines > 0 ) ); + break; + } + } + } + else + { + xi_get_rect( old_focus_obj, &data->focus_cell_rct ); + if ( !xi_move_focus( lmp->itf_obj ) ) + return FALSE; + if (data->nbr_lines == XI_SCROLL_FIRST || data->nbr_lines == XI_SCROLL_LAST) + { /* The old data went away, so the old focus location is no longer valid. */ + lmp->list_obj->v.list->focus_cell->v.cell.row = 0; + lmp->list_obj->v.list->focus_cell->v.cell.column = 0; + lmp->list_obj->v.list->focus_cell->v.cell.is_vert_scrolled = FALSE; + } + } + } + return TRUE; +} + +/*------------------------------------------------------------------------- */ +/* lm_scroll_calc_lines */ +/* if nbr_lines is not an integral, and instead is one of XI_SCROLL_FIRST, */ +/* XI_SCROLL_LAST, XI_SCROLL_PGUP, or XI_SCROLL_PGDOWN, then calculate */ +/* the number of lines. */ +/*------------------------------------------------------------------------- */ +static void +lm_scroll_calc_lines( LM_DATA * lmp, lm_scroll_data * data ) +{ + switch ( data->nbr_lines ) + { +case XI_SCROLL_FIRST: +case XI_SCROLL_LAST: + data->is_first_or_last = TRUE; + break; + case XI_SCROLL_PGUP: +#if XIWS == XIWS_WM + data->nbr_pixels = -( lmp->mlr_height - data->pix_overlap ); +#else + data->nbr_pixels = -( lmp->mlr_height - data->pix_overlap + 1 ); +#endif + data->have_pixels = TRUE; + break; + case XI_SCROLL_PGDOWN: +#if XIWS == XIWS_WM + data->nbr_pixels = lmp->mlr_height - data->pix_overlap; +#else + data->nbr_pixels = lmp->mlr_height - data->pix_overlap + 1; +#endif + data->have_pixels = TRUE; + break; + } +} + +/*------------------------------------------------------------------------- */ +/* lm_scroll_get_initial_rec */ +/*------------------------------------------------------------------------- */ +static BOOLEAN +lm_scroll_get_initial_rec( LM_DATA * lmp, lm_scroll_data * data, + int record_location, LM_CB_TYPE event_type ) +{ + int row_height; + BOOLEAN refused; + + /* first, get rid of all rows, except the focus row */ + lm_remove_all_rows( lmp, FALSE ); + make_rec_available( lmp, ( BOOLEAN ) record_location, ( BOOLEAN ) ! data->have_rec, TRUE ); + if ( data->have_rec ) + { + LM_CELL_DATA *cell_data; + int i; + + lmp->recs[0] = data->rec; + lmp->row_colors[0] = data->color; + lmp->row_attribs[0] = data->attrib; + row_height = data->row_height_arg; + refused = FALSE; + /* cell_data_construct */ + cell_data = lmp->cell_data[0]; + for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data ) + { + memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) ); + lm_xi_text_construct( lmp, 0, i ); + } + } + else + { + refused = do_lm_cb_get( ( LM ) lmp, event_type, &lmp->recs[0], &lmp->recs[0], + data->percent, &lmp->row_colors[0], + &lmp->row_attribs[0], &row_height ); + if ( refused ) + { + lm_do_rec_event( lmp, lmp->nbr_realized_rows - 1, XIE_REC_FREE ); + --lmp->nbr_realized_rows; + calculate_visibles( lmp ); + } + } + if ( !refused ) + { + if ( row_height ) + { + lmp->pix_heights[0] = row_height; + lmp->set_heights[0] = TRUE; + } + else + { + lmp->pix_heights[0] = 0; + lmp->set_heights[0] = FALSE; + } + lmp->pix_offsets[0] = 0; + lmp->pix_heights[0] = lm_calculate_row_height( lmp, 0 ); + lm_invalidate_rows_internal( ( LM ) lmp, 0, 0, FALSE, -1, TRUE ); + } + return !refused; +} + +/*------------------------------------------------------------------------- */ +/* lm_scroll_fill_forward */ +/* returns # of records read if fill previous called, otherwise 0 */ +/*------------------------------------------------------------------------- */ + +static int +lm_scroll_fill_forward( LM_DATA * lmp, BOOLEAN have_rec ) +{ + BOOLEAN refused; + + while ( TRUE ) + { + int idx; + + refused = !get_next_rec( lmp, TRUE ); + if ( refused ) + break; + idx = lmp->nbr_realized_rows - 1; + lmp->pix_heights[idx] = lm_calculate_row_height( lmp, idx ); + if ( idx > 0 ) + lmp->pix_offsets[idx] = lmp->pix_offsets[idx - 1] + + lmp->pix_heights[idx - 1]; + else + lmp->pix_offsets[idx] = 0; + + /* if we finally have enough rows to display the entire list */ + if ( !lmp->get_all_records && ( lmp->pix_offsets[idx] + lmp->pix_heights[idx] + >= lmp->mlr_height ) ) + break; + } + + /* although we have adjusted pix_offsets, and pix_heights, it is still + * necessary to calculate the first and last fully visible rows */ + calculate_visibles( lmp ); + + /* If we have the first record and the list is not full, try getting previous + * records. */ + if ( have_rec && refused ) + return fill_previous( lmp ); + return 0; +} + +/*------------------------------------------------------------------------- */ +/* lm_scroll_first */ +/* returns row # of first record requested - i.e. for xi_scroll_rec, the */ +/* row # of the new record. for scroll first with a percentage, the */ +/* row # of that percentage. Normally 0, but with back-fill, can be */ +/* a positive number. */ +/*------------------------------------------------------------------------- */ +static int +lm_scroll_first( LM_DATA * lmp, lm_scroll_data * data ) +{ + int result = 0; + + if ( lmp->get_all_records && lmp->nbr_realized_rows > 0 ) + { + /* have_rec */ + lmp->rrr_offset = -( int ) ( ( long ) lmp->rrr_bottom * data->percent / 100 ); + calculate_visibles( lmp ); + lmp->rrr_offset = -lmp->pix_offsets[lmp->first_fully_vis]; + } + else + { + if ( lm_scroll_get_initial_rec( lmp, data, REC_AT_BOTTOM, LM_CB_GET_FIRST ) ) + result = lm_scroll_fill_forward( lmp, data->have_rec ); + if ( !lmp->get_all_records ) + { + int nbr_to_free, + cnt, + idx; + + nbr_to_free = lmp->first_fully_vis - 1; + if ( nbr_to_free > 0 ) + { + for ( cnt = 0; cnt < nbr_to_free; cnt++ ) + { + lmp->rrr_offset += lmp->pix_heights[cnt]; + lm_do_rec_event( lmp, cnt, XIE_REC_FREE ); + } + + for ( idx = nbr_to_free; idx < lmp->nbr_realized_rows; ++idx ) + lm_row_copy( lmp, idx, idx - nbr_to_free ); + result -= nbr_to_free; + lm_adjust_rows( lmp, -nbr_to_free ); + lmp->nbr_realized_rows -= nbr_to_free; + } + /* free any unnecessary records at the end of the list */ + nbr_to_free = lmp->nbr_realized_rows - ( lmp->last_fully_vis + 2 ); + for ( idx = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; + cnt < nbr_to_free; idx++, cnt++ ) + lm_do_rec_event( lmp, idx, XIE_REC_FREE ); + lmp->nbr_realized_rows -= cnt; + calculate_pix_offsets( lmp, FALSE ); + { + XI_OBJ *focus_obj; + + focus_obj = lmp->itf_obj->v.itf->focus_obj; + if ( focus_obj && focus_obj->cid == lmp->cid ) + { + if ( focus_obj && focus_obj->type == XIT_CELL ) + { + focus_obj->v.cell.is_vert_scrolled = TRUE; + } + } + } + } + } + return result; +} + +/*------------------------------------------------------------------------- */ +/* lm_scroll_last */ +/* returns row # of requested row */ +/*------------------------------------------------------------------------- */ +static int +lm_scroll_last( LM_DATA * lmp, lm_scroll_data * data ) +{ /* scroll last */ + int result = 0; + + if ( lmp->get_all_records ) + { + if ( lmp->rrr_bottom < lmp->mlr_height ) + lmp->rrr_offset = 0; + else +#if XIWS == XIWS_WM + lmp->rrr_offset = lmp->mlr_height - lmp->rrr_bottom; +#else + lmp->rrr_offset = lmp->mlr_height - lmp->rrr_bottom + 1; +#endif + calculate_visibles( lmp ); + + /* if the page up does not make the first row editable, then scroll the + * exact amount to make it editable */ + if ( -lmp->rrr_offset != + lmp->pix_offsets[lmp->first_fully_vis] ) + { + int p; + + p = lmp->pix_offsets[lmp->first_fully_vis] + + lmp->rrr_offset; + data->nbr_pixels += p; + lmp->rrr_offset -= p; + calculate_visibles( lmp ); + } + } + else + { + data->percent = 0; + if ( lm_scroll_get_initial_rec( lmp, data, REC_AT_TOP, LM_CB_GET_LAST ) ) + { + result = fill_previous( lmp ); + /* get one record after the last record, so that there will not be a gray + * space below the last record, unless there are no more records. */ + get_next_rec( lmp, FALSE ); + calculate_pix_offsets( lmp, FALSE ); + } + } + return result; +} + +/*------------------------------------------------------------------------- */ +/* lm_scroll_calc_pixels */ +/*------------------------------------------------------------------------- */ +static void +lm_scroll_calc_pixels( LM_DATA * lmp, lm_scroll_data * data ) +{ + /* calculate the max number of pixels that we should scroll */ + if ( data->nbr_pixels < 0 ) + { + int p; + + data->nbr_pixels = max( data->nbr_pixels, lmp->rrr_offset ); + lmp->rrr_offset -= data->nbr_pixels; + calculate_visibles( lmp ); + + /* if the page up does not make the first row editable, then scroll the + * exact amount to make it editable */ + if ( -lmp->rrr_offset != + lmp->pix_offsets[lmp->first_fully_vis] ) + { + p = lmp->pix_offsets[lmp->first_fully_vis - 1] + + lmp->rrr_offset; + data->nbr_pixels += p; + lmp->rrr_offset -= p; + calculate_visibles( lmp ); + } + } + else + { + int p; + + calculate_pix_offsets( lmp, FALSE ); + + /* following line puts row coming onto the list at the bottom of the list + * completly on the list. new behavior is to have the row at the top of + * the list to always be completely on the list. nbr_pixels = + * min(nbr_pixels, lmp->rrr_bottom - lmp->mlr_height + lmp->rrr_offset); */ + data->nbr_pixels = max( data->nbr_pixels, 0 ); + lmp->rrr_offset -= data->nbr_pixels; + calculate_visibles( lmp ); + + /* if the page down does not make the first row editable, then scroll the + * exact amount to make it editable */ + if ( -lmp->rrr_offset != + lmp->pix_offsets[lmp->first_fully_vis] ) + { + p = lmp->pix_offsets[lmp->first_fully_vis - 1] + + lmp->rrr_offset; + data->nbr_pixels += p; + lmp->rrr_offset -= p; + calculate_visibles( lmp ); + } + + /* if the page down leaves too much room at the bottom, then make more rows + * visible. */ + while ( TRUE ) + { + int h, + pix_left; + + if ( lmp->first_fully_vis == 0 ) + break; + h = lmp->pix_heights[lmp->first_fully_vis - 1]; + /* Add 1 to pix_left (pixels left in mlr), because it is ok for the pixel + * required for the rule at the bottom of the row to fall below the + * visible portion of the list. */ + pix_left = -( lmp->pix_offsets[lmp->nbr_realized_rows - 1] + + lmp->pix_heights[lmp->nbr_realized_rows - 1] + + lmp->rrr_offset - lmp->mlr_height ) + 1; + if ( pix_left < h ) + break; + data->nbr_pixels -= h; + lmp->rrr_offset += h; + calculate_visibles( lmp ); + } + } +} + +/*------------------------------------------------------------------------- +function: lm_get_scroll_rct +lmp: current lmp +r: pointer to rectangle to be filled in +returns: r +-------------------------------------------------------------------------*/ +XinRect * +lm_get_scroll_rct( LM_DATA * lmp, XinRect * r ) +{ + *r = lmp->mlr; + if ( lmp->pixel_width ) + r->right = r->left + lmp->pixel_width + BORDER_WIDTH - 1; + return r; +} + + +/*------------------------------------------------------------------------- */ +/* lm_scroll_middle */ +/*------------------------------------------------------------------------- */ +static int +lm_scroll_middle( LM_DATA * lmp, lm_scroll_data * data, + BOOLEAN invalidate ) +{ + int recs_read; + + recs_read = 0; + if ( data->have_pixels ) + recs_read = lm_make_rrr_room_pix( lmp, data->nbr_pixels, FALSE ); + else if ( data->nbr_lines ) + { + recs_read = data->nbr_lines; + data->nbr_pixels = make_rrr_room_rows( lmp, &recs_read, FALSE ); + } + lm_scroll_calc_pixels( lmp, data ); + if ( !lmp->get_all_records ) + { + int nbr_to_free, + cnt, + idx; + + nbr_to_free = lmp->first_fully_vis; + if ( nbr_to_free ) + { + for ( cnt = 0; cnt < nbr_to_free; cnt++ ) + { + lmp->rrr_offset += lmp->pix_heights[cnt]; + lm_do_rec_event( lmp, cnt, XIE_REC_FREE ); + } + + for ( cnt = nbr_to_free; cnt < lmp->nbr_realized_rows; ++cnt ) + lm_row_copy( lmp, cnt, cnt - nbr_to_free ); + lm_adjust_rows( lmp, -nbr_to_free ); + lmp->nbr_realized_rows -= nbr_to_free; + } + + calculate_pix_offsets( lmp, FALSE ); + /* free any unnecessary records at the end of the list */ + nbr_to_free = lmp->nbr_realized_rows - ( lmp->last_fully_vis + 2 ); + for ( idx = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; + cnt < nbr_to_free; + idx++, cnt++ ) + lm_do_rec_event( lmp, idx, XIE_REC_FREE ); + lmp->nbr_realized_rows -= cnt; + + for ( idx = lmp->nbr_realized_rows; + idx < lmp->realized_rows_array_len; + ++idx ) + init_row( lmp, idx ); + calculate_pix_offsets( lmp, FALSE ); + } + + if ( invalidate ) + { + XinRect r; + + lm_get_scroll_rct( lmp, &r ); + xi_set_clip( lmp->win, NULL ); + if ( data->nbr_pixels ) + { + XinWindowPaintForce( lmp->win ); + xi_set_update_obj( lmp->list_obj ); + lmp->update_cells_only = TRUE; + xi_scroll_rect( lmp->win, &r, 0, -data->nbr_pixels ); + data->pixels_scrolled = data->nbr_pixels; + } + } + return recs_read; +} + +/*------------------------------------------------------------------------- */ +/* lm_scroll_replace_focus */ +/*------------------------------------------------------------------------- */ +static void +lm_scroll_replace_focus( LM_DATA * lmp, lm_scroll_data * data, + XI_OBJ * old_focus_obj, BOOLEAN same_cell ) +{ + /* put the focus back */ + if ( data->list_had_focus ) + { + if ( old_focus_obj->type == XIT_CELL ) + { + if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + lm_focus_cell_visible_attempt( lmp ); + else + { + if ( same_cell ) + { + int col = old_focus_obj->v.cell.column; + int row, + t, + b; + int max_intersect, + intersect_row; + XI_OBJ cell; + XinRect cell_rct; + int tr; + + max_intersect = 0; + intersect_row = -1; + tr = min( lmp->nbr_realized_rows, lmp->last_fully_vis + 1 ); + for ( row = lmp->first_fully_vis; row < tr; ++row ) + { + XI_MAKE_CELL( &cell, lmp->list_obj, ( unsigned char ) row, + ( unsigned char ) col ); + xi_get_rect( &cell, &cell_rct ); + t = max( cell_rct.top, data->focus_cell_rct.top ); + b = min( cell_rct.bottom, data->focus_cell_rct.bottom ); + if ( ( b - t ) > max_intersect ) + { + max_intersect = b - t; + intersect_row = row; + } + } + if ( intersect_row != -1 ) + { + XI_MAKE_CELL( &cell, lmp->list_obj, ( unsigned char ) intersect_row, + ( unsigned char ) col ); + xi_move_focus( &cell ); + } + } + else + { + switch ( data->scroll_type ) + { + case XI_SCROLL_FIRST: + case XI_SCROLL_PGUP: + data->focus_row = lmp->first_fully_vis; + break; + case XI_SCROLL_LAST: + case XI_SCROLL_PGDOWN: + data->focus_row = lmp->last_fully_vis; + break; + default: + data->focus_row = clip( data->focus_row, lmp->first_fully_vis, + lmp->last_fully_vis ); + break; + } + } + } + } + else + xi_move_focus( old_focus_obj ); + } +} + +/*------------------------------------------------------------------------- +function: lm_scroll +lm: current lm +nbr_lines: nbr of lines to scroll, may be positive or negative, may be set + to XI_SCROLL_FIRST, XI_SCROLL_LAST, XI_SCROLL_PGUP, or XI_SCROLL_PGDN +percent: passed with XI_SCROLL_FIRST event +same_cell: sometimes the focus goes back onto the same cell. In other cases, + for instance, XI_SCROLL_FIRST, XI_SCROLL_LAST, XI_SCROLL_PGUP, and + XI_SCROLL_PGDN, we don't want to put the focus back on the same cell, + but instead, want to put the focus on the first or last fully visible + row. +invalidate: indicates whether to invalidate the list. This is only set to FALSE when + xi_scroll_internal is called when the interface is created. +rec: if have_rec is TRUE, then use rec for the first record, and don't do get first +-------------------------------------------------------------------------*/ +int +lm_scroll( LM_SCROLL_ARG * arg ) +{ + lm_scroll_data data; + int result = 0; + XI_OBJ *old_focus_obj; + LM_DATA *lmp = ( LM_DATA * ) arg->lm; + XI_OBJ *itf = lmp->itf_obj; + BOOLEAN invalidate = !itf->v.itf->half_baked; + BOOLEAN v_scrolled, + focus; + int new_row_height; + int row, + column; + + if ( ( xi_get_attrib( lmp->list_obj ) & XI_ATR_VISIBLE ) == 0 ) + invalidate = FALSE; + lm_scroll_data_construct( lmp, &data, arg ); + /* If the focus is on the first row, and scrolling up, or the focus is on the + * last row and scrolling down, return 0. */ + if ( lmp->get_all_records ) + { + if ( lmp->first_fully_vis == 0 && data.nbr_lines < 0 ) + return 0; + if ( lmp->last_fully_vis == lmp->nbr_realized_rows && + data.nbr_lines > 0 && data.nbr_lines < XI_SCROLL_PGUP ) + return 0; + } + if ( !lmp->itf_obj->v.itf->half_baked && invalidate ) + XinWindowPaintForce( lmp->win ); + old_focus_obj = itf->v.itf->focus_obj; + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + { + focus = lm_focus_cell_get( lmp, &row, &column, &v_scrolled ); + if ( focus && !v_scrolled ) + { + new_row_height = lm_calculate_row_height( lmp, row ); + if ( new_row_height != lmp->pix_heights[row] ) + lm_set_row_height( ( LM ) lmp, row, new_row_height, FALSE, 0, FALSE ); + } + } + if ( !lm_scroll_remove_focus( lmp, &data, old_focus_obj ) ) + return 0; + lm_scroll_calc_lines( lmp, &data ); + if ( data.is_first_or_last ) + { + if ( data.nbr_lines == XI_SCROLL_FIRST ) + result = lm_scroll_first( lmp, &data ); + else + result = lm_scroll_last( lmp, &data ); + if ( invalidate ) + { + XinRect r; + + xi_invalidate_rect( lmp->win, lm_get_scroll_rct( lmp, &r ) ); + } + } + else + { + result = lm_scroll_middle( lmp, &data, invalidate ); + arg->pixels_scrolled = data.pixels_scrolled; + } + + lm_scroll_replace_focus( lmp, &data, old_focus_obj, arg->same_cell ); + if ( lmp->row_focus_border && lmp->nbr_realized_rows > 0 ) + { + int focus_row, + focus_column; + BOOLEAN is_vert_scrolled; + BOOLEAN is_hscrolled; + BOOLEAN is_vis; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &is_vert_scrolled ); + is_vis = lm_focus_cell_is_visible( lmp, &is_hscrolled ); + if ( ( is_vis || is_hscrolled ) && !is_vert_scrolled ) + { + lm_redraw_row( lmp, focus_row, FALSE ); + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + set_focus_cell_rct( lmp, focus_row, focus_column, FALSE ); + } /* is vis */ + } /* focus border */ + do_scroll_bar( lmp->list_obj->v.list ); + if ( invalidate ) + XinWindowPaintForce( lmp->win ); + return result; +} + + +/*------------------------------------------------------------------------- +function: lm_set_text +lm: current lm +s: string to set +row: +column: +-------------------------------------------------------------------------*/ +void +lm_set_text( LM lm, const char *s, int row, int column, BOOLEAN v_scrolled ) +{ + BOOLEAN was_suspended = FALSE; + BOOLEAN preserve_focus_text; + LM_COLUMN_DATA *lmcd; + XinRect rct; + LM_DATA *lmp = LMP( lm ); + + lmcd = lmp->lm_column_data[column]; + if ( row == LM_HEADING_TEXT ) + { + lmcd->heading_text = ( char * ) xi_tree_realloc( lmcd->heading_text, strlen( s ) + 1 ); + strcpy( lmcd->heading_text, s ); + lm_get_cell_rect( &rct, lm, 1, column, FALSE, TRUE ); + rct.top = lmp->pix_hdr_bottom - + max( lmp->pix_cell_height, lmp->min_heading_height + 2 * BORDER_WIDTH ); + rct.bottom = lmp->pix_hdr_bottom; + if ( ( lmp->attrib & LM_ATR_VISIBLE ) != 0 ) + xi_invalidate_rect( lmp->win, &rct ); + } + else + { + int new_row_height; + LM_CELL_DATA *cell_data; + + cell_data = &lmp->cell_data[row][column]; + preserve_focus_text = FALSE; + if ( lm_focus_cell_has( lmp, row, column, v_scrolled ) && lmp->itf_obj->v.itf->chg_flag ) + { + was_suspended = TRUE; + lm_focus_cell_invis_make( lmp ); + preserve_focus_text = TRUE; + } + /* If the cell has focus the XI_TEXT string needs updated */ + if ( lm_focus_cell_has( lmp, row, column, v_scrolled ) ) + { + xi_text_set( cell_data->xi_text, s ); + } + else if ( !v_scrolled ) + xi_text_set( cell_data->xi_text, s ); + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + lm_focus_cell_text_set( lmp, preserve_focus_text, s, row, column, v_scrolled ); + if ( !v_scrolled ) + { + new_row_height = lm_calculate_row_height( lmp, row ); + if ( new_row_height != lmp->pix_heights[row] ) + lm_set_row_height( lm, row, new_row_height, FALSE, 0, FALSE ); + if ( LMP( lm )->attrib & XI_ATR_VISIBLE && LMP( lm )->cell_data[row][column].valid_data ) + redraw_cell( lm, row, column, FALSE ); + } + if ( was_suspended ) + lm_focus_cell_visible_attempt( lmp ); + } +} + + +/*------------------------------------------------------------------------- +function: next cell +lm: current lm +c: character causing the focus to change +next_row: int pointer to be filled in with next row +next_col: int pointer to be filled in with next column +-------------------------------------------------------------------------*/ +static void +next_cell( LM lm, int c, int *next_row, int *next_col, BOOLEAN v_scrolled ) +{ + LM_DATA *lmp = LMP( lm ); + + switch ( c ) + { + case XI_KEY_BTAB: + --*next_col; + if ( *next_col < 0 ) + { + *next_col = lmp->nbr_columns - 1; + if ( ( lmp->attrib & LM_ATR_TABWRAP ) ) + --* next_row; + } + break; + case '\t': + ++*next_col; + if ( *next_col >= lmp->nbr_columns ) + { + *next_col = 0; + if ( ( lmp->attrib & LM_ATR_TABWRAP ) ) + { + if ( *next_row == 255 && v_scrolled ) + *next_row = 0; + else + ++* next_row; + } + } + break; + case XI_KEY_UP: + --*next_row; + break; + case XI_KEY_DOWN: + if ( *next_row == 255 && v_scrolled ) + *next_row = 0; + else + ++* next_row; + break; + case XI_KEY_WLEFT: + case XI_KEY_LEFT: + --*next_col; + if ( *next_col < 0 ) + *next_col = lmp->nbr_columns - 1; + break; + case XI_KEY_WRIGHT: + case XI_KEY_RIGHT: + ++*next_col; + if ( *next_col >= lmp->nbr_columns ) + *next_col = 0; + break; + } +} + + +/*------------------------------------------------------------------------- +function: do_lm_cb +lm: current lm +cb_reason: one of LM_CB_CHAR, LM_CB_CHANGE, LM_CB_FOCUS, LM_CB_REC_ALLOCATE, + LM_CB_REC_FREE +row: relevent row +column: relevent column +ep: xvt event that caused the LM event, used to pass on shift and control +-------------------------------------------------------------------------*/ +BOOLEAN +do_lm_cb( LM lm, LM_CB_TYPE cb_reason, int row, int column, XinEvent * ep, int *percent, int pixels ) +{ + LM_CB_DATA lm_cb_data; + LM_DATA *lmp = LMP( lm ); + + lm_cb_data.lm = lm; + lm_cb_data.cb_type = cb_reason; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) row; + lm_cb_data.column = ( unsigned char ) column; + switch ( cb_reason ) + { + case LM_CB_REC_ALLOCATE: + lm_cb_data.v.rec_allocate.record = lmp->recs[row]; + if ( lm_cb_data.v.rec_allocate.record ) + return FALSE; + break; + case LM_CB_REC_FREE: + lm_cb_data.v.rec_free.record = lmp->recs[row]; + if ( lmp->have_last_rec && lm_cb_data.v.rec_free.record == lmp->last_rec ) + lmp->have_last_rec = FALSE; + if ( !lm_cb_data.v.rec_allocate.record ) + return FALSE; + break; + case LM_CB_CHAR: + lm_cb_data.v.chr.ch = ep->v.character.ch; + lm_cb_data.v.chr.shift = ep->v.character.shift; + lm_cb_data.v.chr.control = ep->v.character.control; + lm_cb_data.v.chr.alt = ep->v.character.alt; + lm_cb_data.v.chr.is_paste = FALSE; + lm_cb_data.v.chr.refused = FALSE; + break; + case LM_CB_CELL_BTN: + if ( ep->type == XinEventCharacter ) + { + lm_cb_data.v.cell_btn.shift = ep->v.character.shift; + lm_cb_data.v.cell_btn.control = ep->v.character.control; + } + else + { + lm_cb_data.v.cell_btn.shift = ep->v.mouse.shift; + lm_cb_data.v.cell_btn.control = ep->v.mouse.control; + } + break; + case LM_CB_GET_PERCENT: + lm_cb_data.v.get_percent.record = lmp->recs[row]; + break; + case LM_CB_ROW_SIZE: + lm_cb_data.v.row_size.new_row_height = pixels; + break; + default: + lm_cb_data.v.refused = FALSE; + break; + } + ( *lmp->lm_cb ) ( &lm_cb_data ); + /* retval = FALSE if event refused */ + switch ( cb_reason ) + { + case LM_CB_REC_ALLOCATE: + lmp->recs[row] = lm_cb_data.v.rec_allocate.record; + return FALSE; + case LM_CB_REC_FREE: + lmp->recs[row] = 0L; + return FALSE; + case LM_CB_CHAR: + if ( !lm_cb_data.v.chr.refused ) + ep->v.character.ch = lm_cb_data.v.chr.ch; + return ( !lm_cb_data.v.chr.refused ); + case LM_CB_GET_PERCENT: + *percent = lm_cb_data.v.get_percent.percent; + return FALSE; + case LM_CB_ROW_SIZE: + return ( !lm_cb_data.v.row_size.refused ); + default: + return ( !lm_cb_data.v.refused ); + } +} + + +/*------------------------------------------------------------------------- +function: do_lm_cb_get +lm: current lm +cb_reason: one of LM_CB_GET_FIRST, LM_CB_GET_LAST, LM_CB_GET_NEXT, + LM_CB_GET_PREV +spec_rec: +data_rec: +percent: +returns: TRUE if event refused +-------------------------------------------------------------------------*/ +BOOLEAN +do_lm_cb_get( LM lm, LM_CB_TYPE cb_reason, long *spec_rec, + long *data_rec, int percent, XinColor * color, + unsigned long *attrib, int *row_height ) +{ + LM_CB_DATA lm_cb_data; + LM_DATA *lmp = LMP( lm ); + + lm_cb_data.lm = lm; + lm_cb_data.cb_type = cb_reason; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.v.rec_request.spec_rec = *spec_rec; + lm_cb_data.v.rec_request.data_rec = *data_rec; + lm_cb_data.v.rec_request.percent = percent; + lm_cb_data.v.rec_request.color = *color; + lm_cb_data.v.rec_request.attrib = *attrib; + lm_cb_data.v.rec_request.refused = FALSE; + ( *lmp->lm_cb ) ( &lm_cb_data ); + if ( cb_reason == LM_CB_GET_NEXT && lm_cb_data.v.rec_request.refused ) + { + lmp->have_last_rec = TRUE; + lmp->last_rec = lm_cb_data.v.rec_request.spec_rec; + } + if ( !lm_cb_data.v.rec_request.refused ) + { + if ( cb_reason == LM_CB_GET_LAST ) + { + lmp->have_last_rec = TRUE; + lmp->last_rec = lm_cb_data.v.rec_request.data_rec; + } + *data_rec = lm_cb_data.v.rec_request.data_rec; + *color = lm_cb_data.v.rec_request.color; + *attrib = lm_cb_data.v.rec_request.attrib; +#if XIWS != XIWS_WM + *row_height = lm_cb_data.v.rec_request.row_height; +#else + *row_height = 0; +#endif + if ( lm_cb_data.v.rec_request.has_focus + && xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + { + if ( lm_focus_rec_get( lmp ) ) + { + lm_cb_data.lm = ( LM ) lmp; + lm_cb_data.cb_type = LM_CB_REC_FREE; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.v.rec_free.record = lm_focus_rec_get( lmp ); + ( *lmp->lm_cb ) ( &lm_cb_data ); + } + lm_focus_rec_set( lmp, *data_rec ); + } + } + return lm_cb_data.v.rec_request.refused; +} + + +static void +calculate_next_cell( LM_DATA * lmp, int *next_row, int *next_col, + BOOLEAN * use_key, int ch, BOOLEAN * off_top, + BOOLEAN * off_bottom ) +{ + BOOLEAN keep_looking; + int focus_row, + focus_column; + BOOLEAN v_scrolled; + + keep_looking = *use_key; + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + *next_row = focus_row; + *next_col = focus_column; + while ( keep_looking ) + { + next_cell( ( LM ) lmp, ch, next_row, next_col, v_scrolled ); + if ( *next_row < 0 ) + { + /* off top logic */ + if ( lmp->get_all_records ) + { + *use_key = FALSE; + break; + } + else + { + keep_looking = FALSE; + *off_top = TRUE; + } + } + else if ( *next_row >= lmp->nbr_realized_rows ) + { + /* off bottom logic */ + if ( lmp->get_all_records ) + { + *use_key = FALSE; + break; + } + else + { + keep_looking = FALSE; + *off_bottom = TRUE; + } + } + else + { + LM_CELL_DATA *cell_data; + + cell_data = &lmp->cell_data[*next_row][*next_col]; + + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, *next_row, *next_col, TRUE ); + if ( CELL_IS_ENABLED( lmp, *next_row, *next_col ) + && !CELL_IS_SELECTABLE( lmp, *next_row, *next_col ) + && lmp->cell_data[*next_row][*next_col].icon_rid == 0 + && lmp->cell_data[*next_row][*next_col].bitmap == NULL ) + + /* found a valid cell */ + keep_looking = FALSE; + } + } +} + + +void +lm_adjust_rows( LM_DATA * lmp, int delta ) +{ + XI_OBJ *focus_obj; + + focus_obj = lmp->itf_obj->v.itf->focus_obj; + if ( focus_obj && focus_obj->cid == lmp->cid ) + { + if ( focus_obj && focus_obj->type == XIT_CELL ) + { + if ( (int)focus_obj->v.cell.row + delta < 0 ) + { + focus_obj->v.cell.is_vert_scrolled = TRUE; + focus_obj->v.cell.row += delta; + return; + } + focus_obj->v.cell.row += delta; + if ( !focus_obj->v.cell.is_vert_scrolled + && ( long ) focus_obj->v.cell.row >= ( long ) lmp->nbr_realized_rows ) + focus_obj->v.cell.is_vert_scrolled = TRUE; + } + if ( focus_obj && focus_obj->type == XIT_ROW ) + focus_obj->v.row += delta; + } +} + +/*------------------------------------------------------------------------- +function: navigate_char_event +lm: current lm +ep: xvt event +returns: TRUE if key was used. +-------------------------------------------------------------------------*/ +BOOLEAN +navigate_char_event( LM lm, XinEvent * ep ) +{ + BOOLEAN use_key = FALSE; + BOOLEAN off_top = FALSE; + BOOLEAN off_bottom = FALSE; + BOOLEAN should_redraw = TRUE; + int next_row, + next_col, + row_inc, + col_inc; + LM_DATA *lmp = LMP( lm ); + short c = ep->v.character.ch; + + if ( !lm_focus_list_has( lmp ) ) + return FALSE; + if ( ( c == '\r' || c == '\n' ) && lmp->itf_obj->v.itf->tab_on_enter) + { + int row, col; + BOOLEAN is_vert_scrolled; + + lm_focus_cell_get( lmp, &row, &col, &is_vert_scrolled ); + if (!lmp->lm_column_data[col]->cr_ok) + { + c = (short)xi_get_pref( XI_PREF_FORM_TAB_CHAR ); + ep->v.character.ch = c; + } + } + switch ( c ) + { + case '\t': + case XI_KEY_BTAB: + case XI_KEY_UP: + case XI_KEY_DOWN: + case XI_KEY_PREV: + case XI_KEY_NEXT: + use_key = TRUE; + break; + case XI_KEY_WRIGHT: + case XI_KEY_WLEFT: + case XI_KEY_LEFT: + case XI_KEY_RIGHT: + if ( ( lmp->attrib & LM_ATR_NAVIGATE ) || ep->v.character.control ) + use_key = TRUE; + break; + } + switch ( c ) + { + case XI_KEY_UP: + case XI_KEY_DOWN: + case XI_KEY_PREV: + case XI_KEY_NEXT: + { + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + { + XI_TEXT *text = xi_text_focus_get( lmp->win ); + + if ( text != 0 && text->multi_line && !ep->v.character.control + && !( lmp->attrib & LM_ATR_NAVIGATE ) ) + return FALSE; + } + switch ( c ) + { + case XI_KEY_PREV: + xi_control_event_scroll( lmp->list_obj, XI_SCROLL_PGUP, 0, TRUE ); + return TRUE; + case XI_KEY_NEXT: + xi_control_event_scroll( lmp->list_obj, XI_SCROLL_PGDOWN, 0, TRUE ); + return TRUE; + } + break; + } + case XI_KEY_WRIGHT: + case XI_KEY_WLEFT: + case XI_KEY_LEFT: + case XI_KEY_RIGHT: + if ( !use_key ) + return FALSE; + } + calculate_next_cell( lmp, &next_row, &next_col, + &use_key, c, &off_top, &off_bottom ); + if ( use_key ) + { + XI_LIST_DATA *list_data; + + list_data = lmp->list_obj->v.list; + if ( off_top || off_bottom ) + { + int old_row_height, + focus_row, + focus_column; + BOOLEAN v_scrolled; + BOOLEAN do_redraw; + + lm_focus_cell_invis_make( lmp ); + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + old_row_height = lmp->pix_heights[focus_row]; + do_redraw = ( lm_calculate_row_height( lmp, focus_row ) != old_row_height ); + if ( off_top ) + make_room_rows( lmp, -1, do_redraw ); + else + make_room_rows( lmp, 1, do_redraw ); + /* calculate next cell again, because the desired next cell may have + * changed. */ + calculate_next_cell( lmp, &next_row, &next_col, &use_key, c, + &off_top, &off_bottom ); + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + row_inc = next_row - focus_row; + col_inc = next_col - focus_column; + next_row = focus_row + row_inc; + if ( next_row >= lmp->nbr_realized_rows ) + next_row = lmp->nbr_realized_rows - 1; + if ( next_row < 0 ) + next_row = 0; + next_col = focus_column + col_inc; + + while ( TRUE ) + { + LM_CELL_DATA *cell_data; + + cell_data = &lmp->cell_data[next_row][next_col]; + + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, next_row, next_col, TRUE ); + if ( CELL_IS_ENABLED( lmp, next_row, next_col ) + && !CELL_IS_SELECTABLE( lmp, next_row, next_col ) + && lmp->cell_data[next_row][next_col].icon_rid == 0 + && lmp->cell_data[next_row][next_col].bitmap == NULL ) + break; + next_cell( lm, off_bottom ? '\t' : + XI_KEY_BTAB, &next_row, &next_col, v_scrolled ); + } + if ( list_data->vert_sync_list && + !list_data->scrolling_in_progress ) + { + XI_OBJ *other_list; + + list_data->scrolling_in_progress = TRUE; + other_list = xi_get_obj( lmp->itf_obj, + list_data->vert_sync_list ); + if ( other_list ) + xi_scroll( other_list, off_top ? -1 : 1 ); + XinWindowPaintForce( lmp->win ); + list_data->scrolling_in_progress = FALSE; + } + XinWindowPaintForce( lmp->win ); + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + if ( focus_row > lmp->last_fully_vis ) + { + LM_FOCUS_CELL_VISIBLE_FORCE_ARGS args; + + MEMCLEAR( args ); + args.lmp = lmp; + args.row = focus_row; + args.column = focus_column; + args.vert_scrolled = v_scrolled; + lm_focus_cell_visible_force( &args ); + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + next_row = focus_row; + calculate_pix_offsets( lmp, FALSE ); + } + lm_focus_cell_visible_attempt( lmp ); + } + + else if ( next_row < lmp->first_fully_vis || next_row > lmp->last_fully_vis ) + { + if ( list_data->vert_sync_list && + !list_data->scrolling_in_progress ) + { + XI_OBJ *other_list; + + list_data->scrolling_in_progress = TRUE; + other_list = xi_get_obj( lmp->itf_obj, + list_data->vert_sync_list ); + if ( other_list ) + xi_scroll( other_list, + next_row < lmp->first_fully_vis ? -1 : 1 ); + XinWindowPaintForce( lmp->win ); + list_data->scrolling_in_progress = FALSE; + } + } + + if ( next_row < lmp->first_fully_vis ) + { + int delta, + idx2, + pix2, + old_pix, + cnt, + height; + XinRect tmp_rct; + + if ( lmp->first_fully_vis == 0 ) + return use_key; + lm_focus_cell_invis_make( lmp ); + idx2 = lmp->first_fully_vis - 1; + pix2 = lmp->pix_offsets[idx2]; + old_pix = -lmp->rrr_offset; + delta = old_pix - pix2; + lmp->rrr_offset += delta; + calculate_pix_offsets( lmp, FALSE ); + if ( !lmp->itf_obj->v.itf->half_baked ) + XinWindowPaintForce( lmp->win ); + xi_set_update_obj( lmp->list_obj ); + lm_get_scroll_rct( lmp, &tmp_rct ); + + /* calculate lmp->update_rows_at_top to speed up scrolling the list */ + height = delta; + for ( cnt = 0; cnt < lmp->nbr_realized_rows && height > 0; ++cnt ) + height -= lmp->pix_heights[cnt]; + lmp->update_rows_at_top = cnt; + + xi_scroll_rect( lmp->win, &tmp_rct, 0, delta ); + do_scroll_bar( lmp->list_obj->v.list ); + lm_focus_cell_visible_attempt( lmp ); + should_redraw = FALSE; + } + + if ( next_row > lmp->last_fully_vis ) + { + int delta, + delta2, + diff, + cnt, + height, + first, + old_row_height, + focus_row; + int idx, + missing; + int focus_column, + new_row_height; + BOOLEAN v_scrolled; + XinRect tmp_rct; + + if ( lmp->last_fully_vis >= lmp->nbr_realized_rows ) + return use_key; + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + old_row_height = lmp->pix_heights[focus_row]; + lm_focus_cell_invis_make( lmp ); + delta = lmp->pix_heights[lmp->first_fully_vis]; + lm_make_rrr_room_pix( lmp, delta, TRUE ); + idx = lmp->last_fully_vis + 1; + missing = lmp->mlr_height - ( lmp->pix_offsets[idx] + lmp->pix_heights[idx] ); + if ( lmp->last_fully_vis + 1 < lmp->nbr_realized_rows ) + delta = max( delta, missing ); + lmp->rrr_offset -= delta; + calculate_pix_offsets( lmp, TRUE ); + calculate_visibles( lmp ); + if ( -lmp->rrr_offset != lmp->pix_offsets[lmp->first_fully_vis] ) + { + delta2 = lmp->pix_offsets[lmp->first_fully_vis] + + lmp->rrr_offset; + lmp->rrr_offset -= delta2; + calculate_pix_offsets( lmp, FALSE ); + calculate_visibles( lmp ); + delta += delta2; + } + diff = lmp->pix_offsets[lmp->nbr_realized_rows - 1] + + lmp->pix_heights[lmp->nbr_realized_rows - 1] - + lmp->mlr_height + lmp->rrr_offset; + if ( !lmp->itf_obj->v.itf->half_baked ) + XinWindowPaintForce( lmp->win ); + if ( diff < 0 ) + lm_make_rrr_room_pix( lmp, -diff, FALSE ); + xi_set_update_obj( lmp->list_obj ); + lm_get_scroll_rct( lmp, &tmp_rct ); + + /* calculate lmp->update_rows_at_bottom to speed up scrolling the list */ + height = lmp->mlr.bottom - lmp->mlr.top - delta; + for ( cnt = 0; cnt < lmp->nbr_realized_rows && height > 0; ++cnt ) + height -= lmp->pix_heights[cnt]; + first = cnt - 1; + height += delta; + for ( ; height > 0; ++cnt ) + height -= lmp->pix_heights[cnt]; + lmp->update_rows_at_bottom = cnt - first; + + /* scroll the list */ + xi_scroll_rect( lmp->win, &tmp_rct, 0, -delta ); + do_scroll_bar( lmp->list_obj->v.list ); + + /* if the row height changed, then we need to redraw the row */ + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + new_row_height = lmp->pix_heights[focus_row]; + if ( new_row_height != old_row_height ) + { + lm_redraw_row( lmp, focus_row, FALSE ); + calculate_pix_offsets( lmp, TRUE ); + } + should_redraw = FALSE; + } + + if ( !lmp->get_all_records ) + { + int nbr_to_free, + cnt, + i, + idx; + + nbr_to_free = lmp->first_fully_vis; + if ( nbr_to_free > 0 ) + { + int rheight; + + rheight = 0; + for ( cnt = 0; cnt < nbr_to_free; cnt++ ) + { + lmp->rrr_offset += lmp->pix_heights[cnt]; + rheight += lmp->pix_heights[cnt]; + lm_do_rec_event( lmp, cnt, XIE_REC_FREE ); + } + + for ( idx = nbr_to_free; idx < lmp->nbr_realized_rows; ++idx ) + lm_row_copy( lmp, idx, idx - nbr_to_free ); + lm_adjust_rows( lmp, -nbr_to_free ); + + /* calculate next cell again, because the desired next cell may have + * changed. */ + calculate_next_cell( lmp, &next_row, &next_col, + &use_key, c, &off_top, &off_bottom ); + lmp->nbr_realized_rows -= cnt; + calculate_pix_offsets( lmp, should_redraw ); + calculate_visibles( lmp ); + lm_make_rrr_room_pix( lmp, rheight, TRUE ); + calculate_pix_offsets( lmp, should_redraw ); + calculate_visibles( lmp ); + } + + /* free any unnecessary records at the end of the list */ + nbr_to_free = lmp->nbr_realized_rows - ( lmp->last_fully_vis + 2 ); + if ( nbr_to_free > 0 ) + { + for ( i = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; cnt < nbr_to_free; + i++, cnt++ ) + lm_do_rec_event( lmp, i, XIE_REC_FREE ); + lmp->nbr_realized_rows -= cnt; + } + + calculate_pix_offsets( lmp, should_redraw ); + + lm_make_rrr_room_pix( lmp, 0, FALSE ); + } + do_lm_cb( lm, LM_CB_FOCUS, next_row, next_col, NULL, NULL, 0 ); + lm_focus_cell_visible_attempt( lmp ); + } + return use_key; +} + + +/*------------------------------------------------------------------------- +function: lm_insert_row +lm: current lm +row: row to insert +-------------------------------------------------------------------------*/ +BOOLEAN +lm_insert_row( LM lm, int row ) +{ + LM_DATA *lmp = LMP( lm ); + + if ( lmp->get_all_records ) + XinError( 20919, XinSeverityFatal, 0L ); + if ( xi_move_focus( lmp->itf_obj ) ) + { + if ( row > 0 && lmp->nbr_realized_rows ) + { + int idx = 0, + row_height, + pix; + XinRect r, + row_rect; + BOOLEAN is_visible; + + row = min( row, lmp->nbr_realized_rows ); + + pix = lmp->pix_offsets[row - 1] + lmp->pix_heights[row - 1] + + 1; + is_visible = ( pix <= lmp->mlr_height - lmp->rrr_offset ); + + if ( is_visible || lmp->get_all_records ) + { + LM_CELL_DATA *cell_data; + int i; + + make_rec_available( lmp, REC_AT_BOTTOM, FALSE, FALSE ); + for ( i = lmp->nbr_realized_rows - 2; i >= row; i-- ) + lm_row_copy( lmp, i, i + 1 ); + idx = row; + /* cell_data_construct */ + cell_data = lmp->cell_data[idx]; + for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data ) + { + memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) ); + lm_xi_text_construct( lmp, idx, i ); + } + lmp->recs[idx] = 0L; + lm_do_rec_event( lmp, idx, XIE_REC_ALLOCATE ); + if ( do_lm_cb_get( ( LM ) lmp, LM_CB_GET_NEXT, + &lmp->recs[idx - 1], &lmp->recs[idx], 0, &lmp->row_colors[idx], + &lmp->row_attribs[idx], &row_height ) ) + { + lm_do_rec_event( lmp, lmp->nbr_realized_rows - 1, XIE_REC_FREE ); + for ( i = row; i < lmp->nbr_realized_rows - 2; ++i ) + lm_row_copy( lmp, i + 1, i ); + --lmp->nbr_realized_rows; + return FALSE; + } + if ( row_height ) + { + lmp->pix_heights[idx] = row_height; + lmp->set_heights[idx] = TRUE; + } + else + { + lmp->pix_heights[idx] = lm_calculate_row_height( lmp, idx ); + lmp->set_heights[idx] = FALSE; + } + + lm_invalidate_rows_internal( ( LM ) lmp, idx, idx, FALSE, -1, TRUE ); + } + + if ( is_visible ) + { + lm_get_scroll_rct( lmp, &r ); + row_height = lm_calculate_row_height( lmp, idx ); + calculate_pix_offsets( lmp, FALSE ); + lm_get_rect( lm, LM_ROW, idx, &row_rect ); + r.top = row_rect.top; + xi_scroll_rect( lmp->win, &r, 0, row_height ); + } + do_scroll_bar( lmp->list_obj->v.list ); + return TRUE; + } + else + { + int idx, + row_height, + cnt; + XinRect r; + BOOLEAN need_first = !lmp->nbr_realized_rows; + + make_rec_available( lmp, REC_AT_TOP, TRUE, FALSE ); + idx = 0; + if ( do_lm_cb_get( ( LM ) lmp, need_first ? LM_CB_GET_FIRST : LM_CB_GET_PREV, + &lmp->recs[idx + 1], &lmp->recs[idx], 0, &lmp->row_colors[idx], + &lmp->row_attribs[idx], &row_height ) ) + { + lm_do_rec_event( lmp, 0, XIE_REC_FREE ); + for ( cnt = 1; cnt < lmp->nbr_realized_rows; ++cnt ) + lm_row_copy( lmp, cnt, cnt - 1 ); + --lmp->nbr_realized_rows; + return FALSE; + } + + if ( row_height ) + { + lmp->pix_heights[idx] = row_height; + lmp->set_heights[idx] = TRUE; + } + else + { + lmp->pix_heights[idx] = lm_calculate_row_height( lmp, idx ); + lmp->set_heights[idx] = FALSE; + } + lm_invalidate_rows_internal( ( LM ) lmp, idx, idx, FALSE, -1, TRUE ); + lm_get_scroll_rct( lmp, &r ); + row_height = lm_calculate_row_height( lmp, idx ); + calculate_pix_offsets( lmp, FALSE ); + xi_scroll_rect( lmp->win, &r, 0, row_height ); + do_scroll_bar( lmp->list_obj->v.list ); + return TRUE; + } + } + return FALSE; +} + + +/*------------------------------------------------------------------------- +function: lm_delete_row +lm: current lm +row: row to delete +-------------------------------------------------------------------------*/ +BOOLEAN +lm_delete_row( LM lm, int row ) +{ + LM_DATA *lmp = LMP( lm ); + + if ( lmp->get_all_records ) + XinError( 20920, XinSeverityFatal, 0L ); + if ( xi_move_focus( lmp->itf_obj ) ) + { + int pix_height, + i; + int recs_read; + XinRect r, + row_rct; + + pix_height = lmp->pix_heights[row]; + lm_get_rect( lm, LM_ROW, row, &row_rct ); + lm_do_rec_event( lmp, row, XIE_REC_FREE ); + for ( i = row + 1; i < lmp->nbr_realized_rows; i++ ) + lm_row_copy( lmp, i, i - 1 ); + lmp->recs[--lmp->nbr_realized_rows] = 0; + calculate_pix_offsets( lmp, FALSE ); + recs_read = lm_make_rrr_room_pix( lmp, pix_height, FALSE ); + pix_height = max( pix_height, 0 ); + lm_get_scroll_rct( lmp, &r ); + r.top = max( r.top, row_rct.top ); + if ( recs_read ) + xi_invalidate_rect( lmp->win, &r ); + else + xi_scroll_rect( lmp->win, &r, 0, -pix_height ); + XinWindowPaintForce( lmp->win ); + do_scroll_bar( lmp->list_obj->v.list ); + } + return TRUE; +} + + +/*------------------------------------------------------------------------- +function: lm_set_row_height +lm: current lm +row: row to set +height: height +-------------------------------------------------------------------------*/ +void +lm_set_row_height( LM lm, int row, int height, BOOLEAN set_height, + int old_height, BOOLEAN only_update ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + int idx = row; + int old_row_height, + delta; + XinRect r, + r2; + + if ( !lmp->itf_obj->v.itf->half_baked ) + XinWindowPaintForce( lmp->win ); + if ( only_update ) + old_row_height = old_height; + else + { + old_row_height = lmp->pix_heights[idx]; + lmp->pix_heights[idx] = height; + lmp->set_heights[idx] = set_height; + } + calculate_pix_offsets( lmp, FALSE ); + + /* Adjust row information */ + if ( !lmp->get_all_records ) + { + if ( height < old_row_height ) + lm_make_rrr_room_pix( lmp, 0, FALSE ); + else + { /* Free rows at bottom */ + int i, + cnt; + int nbr_to_free = lmp->nbr_realized_rows - ( lmp->last_fully_vis + 2 ); + + for ( i = lmp->nbr_realized_rows - nbr_to_free, + cnt = 0; cnt < nbr_to_free; i++, cnt++ ) + lm_do_rec_event( lmp, i, XIE_REC_FREE ); + if ( nbr_to_free > 0 ) + lmp->nbr_realized_rows -= nbr_to_free; + } + } + lm_get_scroll_rct( lmp, &r ); + if ( row < lmp->nbr_realized_rows - 1 ) + { + r.top = lmp->pix_offsets[idx + 1] + lmp->rrr_offset + lmp->mlr.top; + delta = height - old_row_height; + if ( r.top < r.bottom ) + xi_scroll_rect( lmp->win, &r, 0, delta ); + } + lm_get_rect( lm, LM_ROW, row, &r ); + if ( row == lmp->nbr_realized_rows - 1 ) + { + r2 = r; + r2.top = r2.bottom; + r2.bottom = lmp->mlr.bottom; + if ( r2.top < r2.bottom ) + xi_invalidate_rect( lmp->win, &r2 ); + } + xi_invalidate_rect( lmp->win, &r ); +} + + +/*------------------------------------------------------------------------- +function: lm_set_list_size +lm: current lm +height: new height +width: new width +-------------------------------------------------------------------------*/ +void +lm_set_list_size( LM lm, int height, int width ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + XinRect vert_scrollbar_rect; + XinRect horz_scrollbar_rect; + XinRect ir, + old_rct; + int old_height; + int col_offset; + int max_row_height; + int row_height; + int heading_height; + int i; + int row, + col; + XI_LIST_DATA *list_data; + int nbr_to_free, + cnt; + + list_data = lmp->list_obj->v.list; + xi_get_rect( lmp->list_obj, &old_rct ); + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + xi_get_hsb_rect( lmp->list_obj, &horz_scrollbar_rect ); + xi_get_sb_rect( lmp->list_obj, &vert_scrollbar_rect ); + + /* calculate minumum height */ + if ( !list_data->one_row_list ) + { + { + int leading; + int ascent; + int descent; + int char_width; + int font_height; + + xi_get_font_metrics_font( lmp->font, &leading, &ascent, &descent, + &char_width ); + font_height = leading + ascent + descent; + max_row_height = lmp->max_lines_in_cell * font_height + RULE_Y_OFFSET_TOP + + RULE_Y_OFFSET_BOTTOM + RULE_WIDTH_H; + } + for ( i = 0; i < lmp->nbr_realized_rows; ++i ) + { + row_height = lmp->pix_heights[i]; + max_row_height = max( row_height, max_row_height ); + } + heading_height = ( lmp->pix_row1_top - lmp->rct.top ) + BORDER_WIDTH; + i = max_row_height + heading_height + ( horz_scrollbar_rect.bottom + - horz_scrollbar_rect.top ); + height = max( height, i ); + + /* calculate new list metrics */ + lmp->pixel_height = height; + lmp->rct.bottom = lmp->rct.top + height + - ( ( list_data->hsb_win ) ? ( horz_scrollbar_rect.bottom + - horz_scrollbar_rect.top - 1 ) + : 0 ); +#if XIWS == XIWS_WM + lmp->mlr.bottom = lmp->rct.bottom; +#else + lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH; +#endif + old_height = lmp->mlr_height; + lmp->mlr_height = lmp->mlr.bottom - lmp->mlr.top; + calculate_pix_offsets( lmp, FALSE ); + if ( !lmp->get_all_records ) + { + /* fill in with more records */ + if ( old_height < lmp->mlr_height ) + lm_make_rrr_room_pix( lmp, lmp->mlr_height - old_height, FALSE ); + } + + calculate_visibles( lmp ); + } + + if ( width && lmp->pixel_width ) + { + int i, + min_width, + max_col_width; + + max_col_width = 0; + for ( i = lmp->fixed_columns; i < lmp->nbr_columns; ++i ) + max_col_width = max( lmp->lm_column_data[i]->pix_width, max_col_width ); + max_col_width += BORDER_WIDTH; + min_width = ( lmp->vir_left - lmp->rct.left ) + max_col_width + + ( vert_scrollbar_rect.right - vert_scrollbar_rect.left ) + + BORDER_WIDTH + 2 * col_offset; + if ( list_data->sb_win ) + min_width += ( vert_scrollbar_rect.right + - vert_scrollbar_rect.left ); + width = max( min_width, width ); + + lmp->pixel_width = width - ( 2 * BORDER_WIDTH ); + if ( list_data->sb_win ) + lmp->pixel_width -= ( vert_scrollbar_rect.right + - vert_scrollbar_rect.left - 1 ); + lmp->vir_right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH; + } + + /* move scroll bars */ + list_data->have_sb_rct = FALSE; + list_data->have_hsb_rct = FALSE; + xi_move_list_scroll_bar( lmp->list_obj ); + xi_move_list_hscroll_bar( lmp->list_obj ); + lm_set_hscroll_range( lm ); + lm_set_hscroll_bar( lm ); + + ir = lmp->rct; + xi_get_hsb_rect( lmp->list_obj, &horz_scrollbar_rect ); + ir.bottom = horz_scrollbar_rect.bottom + BORDER_WIDTH; + xi_get_sb_rect( lmp->list_obj, &vert_scrollbar_rect ); + ir.right = vert_scrollbar_rect.right + BORDER_WIDTH; + ir.right = max( ir.right, old_rct.right ); + ir.bottom = max( ir.bottom, old_rct.bottom ); + xi_invalidate_rect( lmp->win, &ir ); + + do_scroll_bar( lmp->list_obj->v.list ); + + if ( width && lmp->pixel_width ) + { + /* calculate visible columns */ + i = lm_get_left_most_far_right_col( lmp, lmp->nbr_columns ); + if ( i < lmp->first_vis ) + { + XinWindowPaintForce( lmp->win ); + lm_hscroll( lm, lmp->first_vis - i, 0 ); + } + else + { + lm_calc_last_vis( lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + } + + if ( !lmp->get_all_records ) + { + /* free any unnecessary records at the end of the list */ + nbr_to_free = lmp->nbr_realized_rows - ( lmp->last_fully_vis + 2 ); + for ( i = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; cnt < nbr_to_free; + i++, cnt++ ) + lm_do_rec_event( lmp, i, XIE_REC_FREE ); + lmp->nbr_realized_rows -= cnt; + calculate_visibles( lmp ); + } + + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + for ( row = 0; row < lmp->nbr_realized_rows; ++row ) + { + LM_CELL_DATA *cell_data; + + cell_data = &lmp->cell_data[row][col]; + if ( cell_data->xi_text ) + { + XinRect r; + + r = lmp->mlr; + if ( lmp->pixel_width ) + r.right = r.left + lmp->pixel_width; + xi_text_clip_set( cell_data->xi_text, &r ); + } + } + } +} + +static void +calc_lmp_rct_right( LM_DATA * lmp ) +{ + /* TODO for XINCH mode, need to duplicate algorythm in lm_create */ + /* single-column lists do not have a vertical rule seperating columns */ + if ( lmp->nbr_columns == 0 ) + lmp->rct.right = lmp->rct.left + 2 * BORDER_WIDTH; + else + { + LM_COLUMN_DATA *cell_data = lmp->lm_column_data[lmp->nbr_columns - 1]; + + lmp->rct.right = lmp->rct.left + cell_data->x_pix_pos + cell_data->pix_width + 2 * BORDER_WIDTH + + ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + } + lmp->mlr.right = lmp->rct.right - BORDER_WIDTH; +} + +void +lm_recalc_metrics( LM lm ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + int leading, + ascent, + descent, + font_height, + mch, + i; + XinWindow win; + LM_COLUMN_DATA **cell_data; + int old_char_width; + XI_LIST_DATA *list_data; + XinPoint pnt; + XinRect rct; + + list_data = lmp->list_obj->v.list; + pnt = list_data->xi_pnt; + xi_fu_to_pu( lmp->itf_obj, &pnt, 1 ); + lmp->rct.top = pnt.v; + lmp->rct.left = pnt.h; + + if ( !lmp->resize_with_window ) + { + lmp->pixel_width = list_data->width * + xi_get_fu_width( lmp->itf_obj ) / XI_FU_MULTIPLE; + } + + if ( !lmp->is_list_font ) + lmp->font = lmp->itf_obj->v.itf->font; + if (!lmp->font) + lmp->font = xi_get_system_font(); + win = lmp->win; + XinWindowFontMap( win, lmp->font ); + XinFontMetricsGet( lmp->font, &leading, &ascent, &descent ); + lmp->leading = leading; + lmp->ascent = ascent; + lmp->descent = descent; + font_height = lmp->ascent + lmp->leading + lmp->descent; + lmp->pix_cell_height = font_height + ( RULE_Y_OFFSET_TOP + + RULE_Y_OFFSET_BOTTOM ); +#if XIWS == XIWS_WM + mch = 8; +#else + mch = lmp->min_cell_height; +#endif + lmp->pix_cell_height = max( lmp->pix_cell_height, mch ); + lmp->pix_row_spacing = lmp->pix_cell_height + RULE_WIDTH_H; + lmp->pix_top = lmp->rct.top; + lmp->pix_hdr_bottom = lmp->rct.top + lmp->leading + lmp->ascent + + lmp->descent + BORDER_WIDTH + + RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP + 1; + lmp->pix_hdr_bottom = max( lmp->pix_hdr_bottom, + ( lmp->rct.top + lmp->min_heading_height + 2 * BORDER_WIDTH ) ); + if ( lmp->no_heading ) + lmp->pix_row1_top = lmp->rct.top + BORDER_WIDTH; + else + lmp->pix_row1_top = lmp->pix_hdr_bottom + BORDER_WIDTH; + + old_char_width = lmp->pix_char_width; + lmp->pix_char_width = xi_get_fu_width( lmp->itf_obj ); + calculate_pix_offsets( lmp, FALSE ); + + for ( i = 0, cell_data = lmp->lm_column_data; i < lmp->nbr_columns; ++i, ++cell_data ) + ( *cell_data )->pix_width = ( *cell_data )->pix_width * lmp->pix_char_width / + old_char_width; + + for ( i = 0; i < lmp->nbr_columns; ++i ) + calc_x_pix_pos( lm, lmp->lm_column_data[i], i ); + + calc_lmp_rct_right( lmp ); + + if ( !lmp->resize_with_window ) + { +#if XIWS != XIWS_WM + lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing + + ( BORDER_WIDTH - RULE_WIDTH_H ); +#else + lmp->rct.bottom = lmp->pix_row1_top + lmp->nbr_rows * lmp->pix_row_spacing + + BORDER_WIDTH; +#endif + } + + if ( lmp->fixed_columns >= lmp->nbr_columns ) + lmp->delta_x = 0; + else + lmp->delta_x = lmp->lm_column_data[lmp->first_vis]->x_pix_pos - + lmp->lm_column_data[lmp->fixed_columns]->x_pix_pos; + + lmp->mlr.top = lmp->pix_row1_top; +#if XIWS != XIWS_WM + lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH; +#else + if ( lmp->pixel_width ) + lmp->mlr.bottom = lmp->rct.bottom; + else + lmp->mlr.bottom = lmp->rct.bottom - BORDER_WIDTH; +#endif + lmp->mlr_height = lmp->mlr.bottom - lmp->mlr.top; + + if ( lmp->rrr_bottom < lmp->mlr_height ) + lm_make_rrr_room_pix( lmp, lmp->mlr_height - lmp->rrr_bottom, FALSE ); + + { + XinRect vert_scrollbar_rect; + xi_get_sb_rect( lmp->list_obj, &vert_scrollbar_rect ); + if ( list_data->sb_win ) + lmp->pixel_width -= ( vert_scrollbar_rect.right + - vert_scrollbar_rect.left - 1 ); + lmp->pixel_width = max( lmp->pixel_width, 0 ); + lmp->vir_right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH; + } + + list_data->have_sb_rct = FALSE; + list_data->have_hsb_rct = FALSE; + + xi_get_sb_rect( lmp->list_obj, &rct ); + xi_offset_rect( &rct, -lmp->list_obj->itf->v.itf->delta_x, + -lmp->list_obj->itf->v.itf->delta_y ); + if ( list_data->sb_win ) + XinWindowRectSet( list_data->sb_win, &rct ); + + xi_get_hsb_rect( lmp->list_obj, &rct ); + xi_offset_rect( &rct, -lmp->list_obj->itf->v.itf->delta_x, + -lmp->list_obj->itf->v.itf->delta_y ); + if ( list_data->hsb_win ) + XinWindowRectSet( list_data->hsb_win, &rct ); + + lm_calc_last_vis( lmp ); +} + +void +lm_text_scrolling( XI_OBJ * xi_obj ) +{ + LM_DATA *lmp = ( LM_DATA * ) xi_obj->v.list->lm; + + lmp->text_scrolling = TRUE; +} + +void +lm_set_hscroll_range( LM lm ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + int hscroll_width, + fixed_width, + cnt; + XinRect mlr; + XI_LIST_DATA *listdata; + + if ( lmp->list_obj->nbr_children <= 0 ) + return; + + listdata = lmp->list_obj->v.list; + lm_get_scroll_rct( lmp, &mlr ); + if ( lmp->pixel_width ) + { + int prop; + + hscroll_width = 0; + fixed_width = 0; + for ( cnt = lmp->fixed_columns; cnt < lmp->nbr_columns; ++cnt ) + hscroll_width += lmp->lm_column_data[cnt]->pix_width + lm_get_col_spacing( ); + for ( cnt = 0; cnt < lmp->fixed_columns; ++cnt ) + fixed_width += lmp->lm_column_data[cnt]->pix_width + lm_get_col_spacing( ); + prop = mlr.right - mlr.left - fixed_width - BORDER_WIDTH; + prop = min( prop, hscroll_width ); + prop = max( prop, 0 ); + XinScrollBarSet( listdata->hsb_win, XinScrollBarTypeEither, 0, + hscroll_width, prop, 0 ); + } +} + + +/*------------------------------------------------------------------------- +function: lm_column_set_pixel_width +lm: current lm +idx: column number +width: in pixels +-------------------------------------------------------------------------*/ +void +lm_column_set_pixel_width( LM lm, int idx, int width ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + LM_COLUMN_DATA *column; + XinRect invalid_rct, + old_rct; + int i, + old_width, + new_row_height, + cnt; + + old_rct = lmp->rct; + column = lmp->lm_column_data[idx]; + old_width = column->pix_width; + column->width = width / lmp->pix_char_width; + column->pix_width = width; + for ( i = idx + 1; i < lmp->nbr_columns; ++i ) + calc_x_pix_pos( lm, lmp->lm_column_data[i], i ); + + /* adjust bounding rectangle */ + calc_lmp_rct_right( lmp ); + if ( idx < lmp->fixed_columns ) + lmp->vir_left += column->pix_width - old_width; + + /* The x_pix_pos of the first visible column may have changed so recalculate + * delta_x */ + if ( lmp->fixed_columns >= lmp->nbr_columns ) + lmp->delta_x = 0; + else + lmp->delta_x = lmp->lm_column_data[lmp->first_vis]->x_pix_pos - + lmp->lm_column_data[lmp->fixed_columns]->x_pix_pos; + + invalid_rct = lmp->rct; + invalid_rct.left = column->x_pix_pos; + invalid_rct.right = max( invalid_rct.right, old_rct.right ); + if ( lmp->pixel_width ) + invalid_rct.right = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH; + lmp->list_obj->v.list->have_sb_rct = FALSE; + lmp->list_obj->v.list->have_hsb_rct = FALSE; + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + lm_calc_last_vis( lmp ); + + if ( column->wrap_text ) + { + int first_fully_vis = lmp->first_fully_vis; + int last_row = lmp->nbr_realized_rows - 1; + int height; + + for ( cnt = 0; cnt < lmp->nbr_realized_rows; ++cnt ) + { + int old_row_height; + + old_row_height = lmp->pix_heights[cnt]; + new_row_height = lm_calculate_row_height( lmp, cnt ); + lmp->pix_heights[cnt] = new_row_height; + if ( old_row_height != new_row_height ) + invalid_rct.left = lmp->rct.left; + } + calculate_pix_offsets( lmp, FALSE ); + height = lmp->pix_offsets[last_row] + lmp->pix_heights[last_row] - + lmp->pix_offsets[first_fully_vis]; + if ( height < lmp->mlr_height ) + lm_make_rrr_room_pix( lmp, lmp->mlr_height - height, FALSE ); + if ( !lmp->get_all_records ) + { + int nbr_to_free; + + /* free any unnecessary records at the end of the list */ + nbr_to_free = lmp->nbr_realized_rows - ( lmp->last_fully_vis + 2 ); + for ( i = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; + cnt < nbr_to_free; + i++, cnt++ ) + lm_do_rec_event( lmp, i, XIE_REC_FREE ); + lmp->nbr_realized_rows -= cnt; + calculate_visibles( lmp ); + } + } + lm_invalidate_rect2( lmp, &invalid_rct, TRUE ); +} + + +/*------------------------------------------------------------------------- +function: lm_set_column_width +lm: current lm +idx: column number +width: in characters +-------------------------------------------------------------------------*/ +void +lm_set_column_width( LM lm, int idx, int width ) +{ + lm_column_set_pixel_width( lm, idx, + width * ( ( LM_DATA * ) lm )->pix_char_width ); +} + +/*------------------------------------------------------------------------- +function: lm_get_visible_columns +lm: current lm +first_vis: +last_vis: +-------------------------------------------------------------------------*/ +void +lm_get_visible_columns( LM lm, int *first_vis, int *last_vis ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + + *first_vis = lmp->first_vis; + *last_vis = lmp->last_vis; +} + + +/*------------------------------------------------------------------------- +function: lm_get_list_info +lm: current lm +nbr_recs: number of records +returns: array of record handles +-------------------------------------------------------------------------*/ +long * +lm_get_list_info( LM lm, int *nbr_recs ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + + *nbr_recs = lmp->nbr_realized_rows; + return &lmp->recs[0]; + +} + +/*------------------------------------------------------------------------- +function: lm_cell_request +lm: current lm +lm_part: may be LM_LIST, LM_ROW, LM_COLUMN, or LM_CELL ?? +-------------------------------------------------------------------------*/ +void +lm_cell_request( LM lm, LM_PART lm_part, int idx1, int idx2 ) +{ + LM_DATA *lmp = LMP( lm ); + BOOLEAN redraw; + + redraw = ( BOOLEAN ) ( lmp->attrib & ( LM_ATR_VISIBLE ) ); + lm_focus_cell_invis_make( lmp ); + switch ( lm_part ) + { + case LM_LIST: + lm_invalidate_rows_internal( lm, 0, lmp->nbr_realized_rows - 1, redraw, -1, + FALSE ); + lm_focus_cell_visible_attempt( lmp ); + return; + case LM_ROW: + lm_invalidate_rows_internal( lm, idx1, idx1, redraw, -1, FALSE ); + lm_focus_cell_visible_attempt( lmp ); + return; + case LM_COLUMN: + lm_invalidate_rows_internal( lm, 0, lmp->nbr_realized_rows - 1, redraw, idx1, + FALSE ); + lm_focus_cell_visible_attempt( lmp ); + return; + case LM_CELL: + lm_invalidate_rows_internal( lm, idx1, idx1, redraw, idx2, FALSE ); + lm_focus_cell_visible_attempt( lmp ); + return; + } + XinError( 20918, XinSeverityFatal, 0L ); +} + +/*------------------------------------------------------------------------- +function: lm_get_visible_rows + ------------------------------------------------------------------------- */ +int +lm_get_visible_rows( LM lm, int *first_vis, int *last_vis ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + + if ( first_vis ) + *first_vis = lmp->first_fully_vis; + if ( last_vis ) + *last_vis = lmp->last_fully_vis; + if ( !lmp->nbr_realized_rows ) + return 0; + else + return lmp->last_fully_vis - lmp->first_fully_vis + 1; +} + +/*------------------------------------------------------------------------- +function: lm_get_list_obj +lm: current lm +returns: XI_OBJ * for list +-------------------------------------------------------------------------*/ +XI_OBJ * +lm_get_list_obj( LM lm ) +{ + LM_DATA *lmp = LMP( lm ); + + return ( lmp->list_obj ); +} + +/*------------------------------------------------------------------------- +function: lm_set_buf_size_internal +lm: current lm +part: must be LM_COLUMN +idx: column number +size: the new buffer size +redraw: if TRUE, then redraw the cell +-------------------------------------------------------------------------*/ +static void +lm_set_buf_size_internal( LM lm, LM_PART part, int idx, int size, BOOLEAN redraw ) +{ + int i; + LM_COLUMN_DATA *lmcd; + LM_DATA *lmp = LMP( lm ); + + if ( part != LM_COLUMN ) + XinError( 20917, XinSeverityFatal, 0L ); + lmcd = lmp->lm_column_data[idx]; + lmcd->text_size = size; + + if ( ! lmcd->var_len_text ) + { + for ( i = 0; i < lmp->nbr_realized_rows; i++ ) + { + LM_CELL_DATA *cell_data = &lmp->cell_data[i][idx]; + + xi_text_buffer_size_set( cell_data->xi_text, size ); + if ( redraw && i < lmp->nbr_realized_rows ) + redraw_cell( lm, i, idx, FALSE ); + } + } +} + + +/*------------------------------------------------------------------------- +function: lm_set_buf_size +lm: current lm +part: must be LM_COLUMN +idx: column number +size: the new buffer size +-------------------------------------------------------------------------*/ +void +lm_set_buf_size( LM lm, LM_PART part, int idx, int size ) +{ + lm_set_buf_size_internal( lm, part, idx, size, TRUE ); +} + +/* ------------------------------------------------------------------------ */ +/* adjust_focus_for_column_delete */ +/* if the focus is on a column after the deleted column, adjust the focus */ +/* objects. */ +/* if the focus is on the deleted column, move the focus to the next */ +/* column, previous column, or interface. */ +/* ------------------------------------------------------------------------ */ + +static BOOLEAN +adjust_focus_for_column_delete( LM_DATA * lmp, int column_nbr, + BOOLEAN adjust_focus_column ) +{ + XI_OBJ *focus_obj; + + focus_obj = lmp->itf_obj->v.itf->focus_obj; + if ( focus_obj == NULL || focus_obj->parent != lmp->list_obj + || focus_obj->type != XIT_CELL ) + return TRUE; + + if ( focus_obj->v.cell.column == column_nbr ) + { + XI_OBJ new_cell; + int row, col; + BOOLEAN temp; + + temp = TRUE; + calculate_next_cell( lmp, &row, &col, &temp, '\t', &temp, &temp ); + if ( row != focus_obj->v.cell.row ) + { + temp = TRUE; + calculate_next_cell( lmp, &row, &col, &temp, XI_KEY_BTAB, &temp, &temp ); + } + if ( row == focus_obj->v.cell.row ) + { + XI_MAKE_CELL( &new_cell, lmp->list_obj, row, col ); + if ( !xi_move_focus( &new_cell ) ) + return FALSE; + if ( adjust_focus_column && + ( int ) focus_obj->v.cell.column > ( int ) column_nbr ) + { + focus_obj = lmp->itf_obj->v.itf->focus_obj; + focus_obj->v.cell.column--; + } + return TRUE; + } + return xi_move_focus( lmp->itf_obj ); + } + if ( adjust_focus_column && + ( int ) focus_obj->v.cell.column > ( int ) column_nbr ) + focus_obj->v.cell.column--; + return TRUE; +} + +/*------------------------------------------------------------------------- +function: lm_delete_column +lm: current lm +column_nbr: column to delete +adjust_hscrolling: if TRUE, then make more horizontal columns visible +-------------------------------------------------------------------------*/ +void +lm_delete_column( LM lm, int column_nbr, BOOLEAN adjust_hscrolling ) +{ + LM_DATA *lmp = LMP( lm ); + LM_COLUMN_DATA *lmcd; + XinRect invalid_rct, + old_rct; + int i, + old_width, + old_left, + col_spacing; + int old_x_pix_pos; + LM_CELL_DATA *cell_data; + + if ( !adjust_focus_for_column_delete( lmp, column_nbr, TRUE ) ) + return; + col_spacing = lm_get_col_spacing( ); + if ( column_nbr >= lmp->nbr_columns ) + XinError( 20915, XinSeverityFatal, 0L ); + old_rct = lmp->rct; + lmcd = lmp->lm_column_data[column_nbr]; + if ( lmcd->font ) + XinFontDestroy( lmcd->font ); + xi_bitmap_destroy( lmcd->bitmap ); + old_left = lmcd->x_pix_pos - lmp->delta_x; + old_x_pix_pos = lmcd->x_pix_pos; + old_width = lmcd->pix_width; + xi_tree_free( lmp->lm_column_data[column_nbr] ); + + /* cell_data_destruct */ + for ( i = 0; i < lmp->nbr_realized_rows; ++i ) + { + cell_data = &( lmp->cell_data[i][column_nbr] ); + if ( cell_data->font ) + XinFontDestroy( cell_data->font ); + xi_bitmap_destroy( cell_data->bitmap ); + xi_bitmap_destroy( cell_data->button_bitmap ); + if ( cell_data->xi_text ) + xi_text_destruct( cell_data->xi_text ); + } + + for ( i = 0; i < lmp->realized_rows_array_len; ++i ) + { + int j; + + for ( j = column_nbr; j < lmp->nbr_columns - 1; ++j ) + lmp->cell_data[i][j] = lmp->cell_data[i][j + 1]; + lmp->cell_data[i] = ( LM_CELL_DATA * ) xi_tree_realloc( lmp->cell_data[i], + ( lmp->nbr_columns - 1 ) * sizeof( LM_CELL_DATA ) ); + } + + for ( i = column_nbr; i < lmp->nbr_columns - 1; ++i ) + lmp->lm_column_data[i] = lmp->lm_column_data[i + 1]; + --lmp->nbr_columns; + { /* Check focus cell, to see if it is now out of range */ + XI_OBJ* focus_cell; + + focus_cell = lmp->list_obj->v.list->focus_cell; + if ( (int)focus_cell->v.cell.column >= lmp->nbr_columns ) + focus_cell->v.cell.column = lmp->nbr_columns - 1; + } + + for ( i = column_nbr; i < lmp->nbr_columns; ++i ) + calc_x_pix_pos( lm, lmp->lm_column_data[i], i ); + + calc_lmp_rct_right( lmp ); + + /* adjust left border of horizontal virtual space */ + if ( column_nbr < lmp->fixed_columns ) + lmp->vir_left -= ( old_width + col_spacing ); + + + /* if the column is invisible */ + calculate_pix_offsets( lmp, TRUE ); + if ( column_nbr >= lmp->fixed_columns && old_x_pix_pos < lmp->delta_x ) + { + lmp->delta_x -= ( old_width + lm_get_col_spacing( ) ); + --lmp->first_vis; + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + else + { + if ( column_nbr < lmp->fixed_columns ) + { + --lmp->first_vis; + --lmp->fixed_columns; + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + + invalid_rct = lmp->rct; + invalid_rct.left = old_left; + invalid_rct.right = max( invalid_rct.right, old_rct.right ); + if ( lmp->pixel_width ) + invalid_rct.right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH; + + /* if we add the following two lines in, it prevents flashing of the top + * and bottom borders when moving columns, however, the top and bottom + * borders need to get invalidated invalid_rct.top += BORDER_WIDTH; + * invalid_rct.bottom -= BORDER_WIDTH; */ + + lm_invalidate_rect2( lmp, &invalid_rct, FALSE ); + lmp->list_obj->v.list->have_sb_rct = FALSE; + lmp->list_obj->v.list->have_hsb_rct = FALSE; + + i = lm_get_left_most_far_right_col( lmp, lmp->nbr_columns ); + /* All columns have been deleted */ + if ( i == 0 ) + { + lmp->delta_x = 0; + lmp->last_vis = lmp->first_vis = i; + lm_calc_last_vis( lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + return; + } + if ( lmp->first_vis >= lmp->nbr_columns ) + { + XinRect r; + + XinWindowPaintForce( lmp->win ); + if ( i < lmp->nbr_columns ) + lmp->delta_x = lmp->lm_column_data[i]->x_pix_pos - lmp->vir_left; + else + lmp->delta_x = 0; + xi_set_update_obj( lmp->list_obj ); + lmp->last_vis = lmp->first_vis = i; + lm_calc_last_vis( lmp ); + r.left = lmp->vir_left; + r.right = lmp->vir_right; +#if XIWS != XIWS_WM + r.top = lmp->rct.top + BORDER_WIDTH; + r.bottom = lmp->rct.bottom - BORDER_WIDTH; +#else + r.top = lmp->rct.top; + r.bottom = lmp->rct.bottom; +#endif + xi_invalidate_rect( lmp->win, &r ); + XinWindowPaintForce( lmp->win ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + else + { + if ( i < lmp->first_vis && adjust_hscrolling ) + { + XinWindowPaintForce( lmp->win ); + lm_hscroll( lm, i - lmp->first_vis, 0 ); + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + else + { + lm_calc_last_vis( lmp ); + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + } + } +} + +/* +TODO this function will change. pix_row_spacing will no longer be used. +instead, min_row_height, and absolute_height will be used. +*/ + +/*------------------------------------------------------------------------- + lm_get_vertical_metrics +-------------------------------------------------------------------------*/ +void +lm_get_vertical_metrics( XI_OBJ_DEF * obj_def, int *first_row_y, + int *row_spacing, int *client_height, + int *title_height ) +{ + XI_LIST_DEF *list_def; + XI_OBJ_DEF *itf_def; + int leading, + ascent, + descent, + char_width, + font_height, + pix_cell_height, + pix_hdr_bottom, + min_cell_height; + XinPoint p; + XinFont *fontp = NULL; + + list_def = obj_def->v.list; + +#if XIWS != XIWS_WM + itf_def = obj_def->parent; + if ( itf_def && itf_def->v.itf->font ) + fontp = itf_def->v.itf->font; + if ( list_def->font ) + xi_get_font_metrics_font( list_def->font, &leading, &ascent, + &descent, &char_width ); + else if ( fontp ) + xi_get_font_metrics_font( fontp, &leading, &ascent, &descent, + &char_width ); + else + xi_get_font_metrics_font( xi_get_system_font( ), &leading, + &ascent, &descent, &char_width ); +#else + leading = 0; + ascent = 8; + descent = 0; +#endif + font_height = ascent + leading + descent; +#if XIWS == XIWS_WM + min_cell_height = 8; + pix_cell_height = font_height; +#else + min_cell_height = list_def->min_cell_height; + pix_cell_height = font_height + CELL_VERTICAL_MARGIN; +#endif + pix_cell_height = max( pix_cell_height, min_cell_height ); +#if XIWS == XIWS_WM + *row_spacing = pix_cell_height; +#else + *row_spacing = pix_cell_height + RULE_WIDTH_H; +#endif + itf_def = obj_def->parent; + if ( itf_def && itf_def->v.itf->font ) + fontp = itf_def->v.itf->font; + if ( xi_def_get_xil_pref( itf_def ) ) + { + p = list_def->xi_pnt; + } + else + { + p = list_def->pixel_origin; + if ( !p.v && !p.h ) + { + p = list_def->xi_pnt; + if ( list_def->font ) + xi_fu_to_pu_font( list_def->font, &p, 1 ); + else if ( fontp ) + xi_fu_to_pu_font( fontp, &p, 1 ); + else + xi_fu_to_pu_font( xi_get_system_font( ), &p, 1 ); + } + } +#if XIWS != XIWS_WM + pix_hdr_bottom = p.v + leading + ascent + descent + BORDER_WIDTH + + RULE_Y_OFFSET_BOTTOM + RULE_Y_OFFSET_TOP + 1; + pix_hdr_bottom = max( pix_hdr_bottom, p.v + list_def->min_heading_height + + BORDER_WIDTH ); +#else + pix_hdr_bottom = p.v + leading + ascent + descent + BORDER_WIDTH; + pix_hdr_bottom = max( pix_hdr_bottom, p.v + list_def->min_heading_height ); +#endif + if ( list_def->no_heading ) + { + int first_row_y_pos = p.v + BORDER_WIDTH; + + *first_row_y = first_row_y_pos; + } + else + { + *first_row_y = pix_hdr_bottom + BORDER_WIDTH; + } + if ( xi_def_get_xil_pref( itf_def ) ) + { + *client_height = list_def->height; + } + else + { + if ( list_def->pixel_height ) + *client_height = list_def->pixel_height; + else + { + int height; + + if ( list_def->font ) + height = xi_get_fu_height_font( list_def->font ); + else if ( fontp ) + height = xi_get_fu_height_font( fontp ); + else + height = xi_get_fu_height_font( xi_get_system_font( ) ); + *client_height = list_def->height * height / XI_FU_MULTIPLE; + } + } + *title_height = *first_row_y - p.v; + *client_height -= *title_height + BORDER_WIDTH; +} + + +/*------------------------------------------------------------------------- +function: lm_get_metrics +lm_def: definition of a list +hborder: to be filled in with the horizontal border width +column_div: to be filled in with the column spacing in pixels +list_bottom: bottom of the list, in pixels +-------------------------------------------------------------------------*/ +void +lm_get_metrics( XI_OBJ_DEF * obj_def, int *hborder, int *column_div, + int *list_bottom ) +{ + if ( hborder != NULL ) + *hborder = BORDER_WIDTH; + if ( column_div != NULL ) + *column_div = lm_get_col_spacing( ); + if ( obj_def->v.list ) + { + int pix_row_spacing, + nbr_rows, + height, + pix_row1_top, + title_height; + + lm_get_vertical_metrics( obj_def, &pix_row1_top, &pix_row_spacing, + &height, &title_height ); + if ( obj_def->v.list->one_row_list ) + nbr_rows = 1; + else + nbr_rows = height / pix_row_spacing; +#if XIWS == XIWS_WM + *list_bottom = pix_row1_top + nbr_rows * pix_row_spacing + BORDER_WIDTH; +#else + *list_bottom = pix_row1_top + nbr_rows * pix_row_spacing + + ( BORDER_WIDTH - RULE_WIDTH_H ); +#endif + } +} + + +/*------------------------------------------------------------------------- +function: lm_set_hscroll_bar +lm: current lm +notes: Calculate the percentage for the horizontal scroll bar, and set the + thumb position on the horizontal scroll bar. +-------------------------------------------------------------------------*/ +void +lm_set_hscroll_bar( LM lm ) +{ + XI_OBJ *list_obj; + int p; + LM_DATA *lmp; + int rng1, + rng2; + int prop; + + lmp = ( LM_DATA * ) lm; + list_obj = lmp->list_obj; + if ( list_obj->v.list->hsb_win ) + { + XinScrollBarRangeGet( list_obj->v.list->hsb_win, XinScrollBarTypeEither, + &rng1, &rng2 ); + prop = XinScrollBarProportionGet( list_obj->v.list->hsb_win, XinScrollBarTypeEither ); + p = lmp->delta_x; + if ( p > rng2 - prop ) + p = rng2 - prop; + XinScrollBarPositionSet( list_obj->v.list->hsb_win, XinScrollBarTypeEither, + p ); + } +} + +/*------------------------------------------------------------------------- +function: lm_create_column +lcdef: column definition +not_creating_list: if TRUE, do all of the cell requests for the column +in_hscrolling: if TRUE, and if on border between fixed and scrolling columns +-------------------------------------------------------------------------*/ +void +lm_create_column( LM lm, LM_COLUMN_DEF * lcdef, BOOLEAN not_creating_list, + BOOLEAN in_hscrolling ) +{ + LM_COLUMN_DATA *lcdata; + LM_COLUMN_DATA **column_data; + LM_DATA *lmp = LMP( lm ); + XinRect rct_to_invalidate; + int i; + int position, + col_spacing; + int focus_row, + focus_column; + BOOLEAN made_invis = FALSE; + + col_spacing = lm_get_col_spacing( ); + position = min( lcdef->position, lmp->nbr_columns ); + if ( lm_focus_list_has( lmp ) ) + { + BOOLEAN v_scrolled; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + if ( focus_column >= position ) + ++focus_column; + lm_focus_cell_set( lmp, focus_row, focus_column, v_scrolled ); + if ( lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE ) + { + lm_focus_cell_invis_make( lmp ); + made_invis = TRUE; + } + } + lcdata = ( LM_COLUMN_DATA * ) xi_tree_malloc( sizeof( LM_COLUMN_DATA ), + ( char * ) lm ); + lcdata->attrib = lcdef->attrib; +/* + lcdata->pix_width = lcdef->width * lmp->pix_char_width; + lcdata->width = lcdef->width; +*/ + lcdata->pix_width = lcdef->pix_width; + lcdata->width = lcdef->pix_width / lmp->pix_char_width; + calc_x_pix_pos( lm, lcdata, position ); + lcdata->text_size = lcdef->text_size; + lcdata->center_heading = lcdef->center_heading; + lcdata->heading_well = lcdef->heading_well; + lcdata->heading_platform = lcdef->heading_platform; + lcdata->column_well = lcdef->column_well; + lcdata->column_platform = lcdef->column_platform; + lcdata->heading_text = ( char * ) xi_tree_malloc( + strlen( lcdef->heading_text ) + 1, ( char * ) lm ); + strcpy( lcdata->heading_text, lcdef->heading_text ); + if ( lcdef->font ) + lcdata->font = lcdef->font; + lcdata->icon_rid = lcdef->icon_rid; + lcdata->icon_x = lcdef->icon_x; + lcdata->icon_y = lcdef->icon_y; + lcdata->bitmap = lcdef->bitmap; + lcdata->size_rows = lcdef->size_rows; + lcdata->suppress_update_heading = lcdef->suppress_update_heading; + lcdata->suppress_update_cells = lcdef->suppress_update_cells; + lcdata->vertical_align_center = lcdef->vertical_align_center; + lcdata->vertical_align_bottom = lcdef->vertical_align_bottom; + lcdata->wrap_text = lcdef->wrap_text; + lcdata->wrap_text_scrollbar = lcdef->wrap_text_scrollbar; + lcdata->cr_ok = lcdef->cr_ok; + lcdata->var_len_text = lcdef->var_len_text; + lcdata->auto_tab = lcdef->auto_tab; + lcdata->icon_mode = lcdef->icon_mode; + + /* allocate new columns */ + column_data = lmp->lm_column_data = + ( LM_COLUMN_DATA * * ) xi_tree_realloc2( + ( char * ) lmp->lm_column_data, + sizeof( LM_COLUMN_DATA * ) * ( lmp->nbr_columns + 1 ), + ( char * ) lm ); + + /* move column pointers around in the column list */ + for ( i = lmp->nbr_columns; i > position; i-- ) + { + column_data[i] = column_data[i - 1]; + column_data[i]->x_pix_pos += lcdata->pix_width + col_spacing; + } + column_data[position] = lcdata; + + lmp->nbr_columns++; + + /* create space for cell data */ + /* cell_data_construct */ + for ( i = 0; i < lmp->realized_rows_array_len; i++ ) + { + int j; + + lmp->cell_data[i] = ( LM_CELL_DATA * ) xi_tree_realloc( lmp->cell_data[i], + ( lmp->nbr_columns + 1 ) * sizeof( LM_CELL_DATA ) ); + for ( j = lmp->nbr_columns; j > position; j-- ) + lmp->cell_data[i][j] = lmp->cell_data[i][j - 1]; + memset( ( char * ) &lmp->cell_data[i][position], '\0', + sizeof( LM_CELL_DATA ) ); + } + + if ( not_creating_list ) + { + for ( i = 0; i < lmp->nbr_realized_rows; ++i ) + lm_xi_text_construct( lmp, i, position ); + } + + if ( ( not_creating_list ) && ( position < lmp->fixed_columns ) ) + { + lmp->first_vis++; + lmp->fixed_columns++; + } + + if ( not_creating_list && ( !in_hscrolling ) && position == lmp->fixed_columns ) + { + lmp->first_vis++; + lmp->fixed_columns++; + } + + if ( lmp->first_vis < lmp->fixed_columns && + lmp->nbr_columns > lmp->fixed_columns ) + lmp->first_vis = lmp->fixed_columns; + + /* adjust bounding rectangle */ + calc_lmp_rct_right( lmp ); + + /* calculate the left boundary of the virtual space for the list */ + lmp->vir_left = lmp->rct.left + BORDER_WIDTH; + for ( i = 0; i < min( lmp->nbr_columns, lmp->fixed_columns ); ++i ) + { + lmp->vir_left += lmp->lm_column_data[i]->pix_width; + lmp->vir_left += col_spacing; + } + if ( not_creating_list ) + { + lm_invalidate_rows_internal( lm, 0, INT_MAX, FALSE, position, TRUE ); + calculate_pix_offsets( lmp, TRUE ); + } + if ( position >= lmp->fixed_columns && column_data[position]->x_pix_pos < lmp->delta_x ) + { + lmp->delta_x += ( column_data[position]->pix_width + lm_get_col_spacing( ) ); + ++lmp->first_vis; + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + else + { + /* invalidate changed rectangle */ + lm_get_list_rct( lmp, &rct_to_invalidate ); + + /* if we add the following two lines in, it prevents flashing of the top + * and bottom borders when moving columns, however, the top and bottom + * borders need to get invalidated rct_to_invalidate.top += BORDER_WIDTH; + * rct_to_invalidate.bottom -= BORDER_WIDTH; */ + + rct_to_invalidate.left = lcdata->x_pix_pos; + lm_adj_h( lmp, &rct_to_invalidate.left ); + if ( rct_to_invalidate.bottom > rct_to_invalidate.top && + rct_to_invalidate.right > rct_to_invalidate.left ) + lm_invalidate_rect2( lmp, &rct_to_invalidate, FALSE ); + } + lm_calc_last_vis( lmp ); + lmp->list_obj->v.list->have_sb_rct = FALSE; + if ( not_creating_list && lmp->list_obj->v.list->hsb_win ) + { + XinRect rct; + + lmp->list_obj->v.list->have_hsb_rct = FALSE; + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + xi_get_hsb_rect( lmp->list_obj, &rct ); + xi_offset_rect( &rct, -lmp->list_obj->itf->v.itf->delta_x, + -lmp->list_obj->itf->v.itf->delta_y ); + XinWindowRectSet( lmp->list_obj->v.list->hsb_win, &rct ); + } + if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + { + if ( not_creating_list && made_invis ) + lm_focus_cell_visible_attempt( lmp ); + } +} + +/*------------------------------------------------------------------------- +function: do_lm_cb_column +lm: current lm +cb_reason: one of LM_CB_COL_DELETE, LM_CB_COL_MOVE, LM_CB_COL_SIZE +col_nbr: column being deleted, moved, or re-sized +new_col_nbr: new column number on LM_CB_COL_MOVE +new_col_width: new column width on LM_CB_COL_SIZE +new_col_pixel_width: new column pixel width on LM_CB_COL_SIZE +in_fixed: if TRUE, then column is being moved to fixed portion of list +returns: TRUE if event refused +-------------------------------------------------------------------------*/ +static BOOLEAN +do_lm_cb_column( LM lm, LM_CB_TYPE cb_reason, int col_nbr, + int new_col_nbr, int new_col_width, int new_col_pixel_width, + BOOLEAN in_fixed ) +{ + LM_CB_DATA lm_cb_data; + + lm_cb_data.lm = lm; + lm_cb_data.cb_type = cb_reason; + lm_cb_data.cid = LMP( lm )->cid; + lm_cb_data.win = LMP( lm )->win; + lm_cb_data.column = ( unsigned char ) col_nbr; + lm_cb_data.v.column.new_col_nbr = new_col_nbr; + lm_cb_data.v.column.in_fixed = in_fixed; + lm_cb_data.v.column.new_col_width = new_col_width; + lm_cb_data.v.column.new_col_pixel_width = new_col_pixel_width; + lm_cb_data.v.column.refused = FALSE; + ( *LMP( lm )->lm_cb ) ( &lm_cb_data ); + return ( lm_cb_data.v.column.refused ); +} + +/*------------------------------------------------------------------------- +function: get_rubber_rect +lmp: current lmp +rctp: rectangle to be filled in +x: current mouse x position +y: current mouse y position +-------------------------------------------------------------------------*/ +static void +get_rubber_rect( LM_DATA * lmp, XinRect * rctp, int x, int y, + BOOLEAN last_in_hscrolling ) +{ + XinRect rct; + + if ( lmp->moving_column ) + { + int col, + delta_x, + delta_y; + + col = lmp->column_being_moved; + /* lm_get_cell_rect returns the exact physical rectangle of the cell - not + * shifted to the right or to the left. */ + lm_get_cell_rect( &rct, ( LM ) lmp, 1, col, FALSE, TRUE ); + rct.top = lmp->pix_top + BORDER_WIDTH; + rct.bottom = lmp->pix_hdr_bottom; + delta_x = x - lmp->org_x; + if ( lmp->down_in_hscrolling && !last_in_hscrolling ) + delta_x += lmp->delta_x; + if ( !lmp->down_in_hscrolling && last_in_hscrolling ) + delta_x -= lmp->delta_x; + delta_y = y - lmp->org_y; + rct.left += delta_x; + rct.right += delta_x; + rct.top += delta_y; + rct.bottom += delta_y; + } + else + { + lm_get_rect( ( LM ) lmp, LM_LIST, 0, &rct ); + rct.top = y; + rct.bottom = rct.top + lmp->drag_row_height; + rct.right += x - rct.left; + rct.left = x; + } + *rctp = rct; +} + + +/*------------------------------------------------------------------------- +function: rubber_rect +lmp: current lmp +-------------------------------------------------------------------------*/ +static void +rubber_rect( LM_DATA * lmp ) +{ +#if XIWS != XIWS_WM + XinRect rct; + XinDrawTools new_ctools; + XinWindow win = lmp->win; + + if ( lmp->last_itf ) + win = xi_get_window( lmp->last_itf ); + + XinWindowDrawToolsNormalGet( &new_ctools ); + XinWindowDrawToolsSet( win, &new_ctools ); + XinWindowPenSet( win, &rubber_cpen ); + XinWindowBrushSet( win, &hollow_cbrush ); + XinWindowDrawModeSet( win, XinDrawModeXor ); + xi_set_clip( win, NULL ); + get_rubber_rect( lmp, &rct, lmp->last_x, lmp->last_y, lmp->last_in_hscrolling ); + xi_draw_rect( win, &rct ); +#else + NOREF( lmp ); +#endif +} + +/*------------------------------------------------------------------------- +function: lm_move_event +lmp: current lmp +ep: xvt event +-------------------------------------------------------------------------*/ +#define XI_AUTOSCROLL_COUNT 8 /* Number of move events before autoscroll + * occurs */ +#define XI_AUTOSCROLL_FAST 50 /* Number of pixels to get to fast autoscroll */ + +void +lm_move_event( LM_DATA * lmp, XinEvent * ep ) +{ + XinPoint where; + int col_offset; + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + where = ep->v.mouse.where; + switch ( ep->type ) + { + case XinEventMouseDown: + case XinEventMouseDouble: + lmp->last_x = where.h; + lmp->org_x = lmp->last_x; + lmp->last_y = where.v; + lmp->org_y = lmp->last_y; + lmp->last_in_hscrolling = lmp->in_hscrolling; + rubber_rect( lmp ); + break; + case XinEventMouseMove: + { + static int autoscroll_count = 0; + BOOLEAN scrolled = FALSE; + + if ( lmp->pixel_width != 0 ) + { /* Check for autoscroll */ + if ( where.h - lmp->delta_x > lmp->vir_right ) + { + if ( where.h - lmp->delta_x > lmp->vir_right + XI_AUTOSCROLL_FAST + || ++autoscroll_count >= XI_AUTOSCROLL_COUNT ) + { + autoscroll_count = 0; + rubber_rect( lmp ); + lm_hscroll( ( LM ) lmp, 1, 0 ); + scrolled = TRUE; + } + } + else if ( where.h < lmp->vir_left ) + { + if ( where.h < lmp->vir_left - XI_AUTOSCROLL_FAST + || ++autoscroll_count >= XI_AUTOSCROLL_COUNT ) + { + autoscroll_count = 0; + rubber_rect( lmp ); + lm_hscroll( ( LM ) lmp, -1, 0 ); + scrolled = TRUE; + } + } + } + else + autoscroll_count = 0; + if ( scrolled || where.h != lmp->last_x || where.v != lmp->last_y ) + { + if ( !scrolled ) + rubber_rect( lmp ); + lmp->last_x = where.h; + lmp->last_y = where.v; + lmp->last_in_hscrolling = lmp->in_hscrolling; + rubber_rect( lmp ); + } + break; + } + case XinEventMouseUp: + { + int column; + XI_OBJ *list_obj, + **members; + int nbr_members, + col_cnt, + temp1, + temp2, + dist1, + dist2, + min_dist, + position; + XinRect rct; + XinPoint where; + + where = ep->v.mouse.where; + rubber_rect( lmp ); + column = lmp->column_being_moved; + list_obj = lmp->list_obj; + if ( list_obj ) + get_rubber_rect( lmp, &rct, where.h, where.v, lmp->in_hscrolling ); + if ( lmp->drop_and_delete && + ( rct.bottom < ( lmp->pix_top - 8 ) || + rct.top > ( lmp->pix_row1_top + 8 ) ) ) + { + /* If the focus is in the column to be deleted, we will move focus as if + the tab key had been pressed before deleting the col. This is so the + Bridge doesn't try to reference a deleted column object in the + OFF_CELL event. */ + XI_OBJ *old_focus; + BOOLEAN deleteable = TRUE; + BOOLEAN return_focus = FALSE; + + old_focus = lmp->itf_obj->v.itf->focus_obj; + if (old_focus->type == XIT_CELL && old_focus->parent == lmp->list_obj + && old_focus->v.cell.column == column) + { + if (adjust_focus_for_column_delete( lmp, column, FALSE )) + return_focus = TRUE; + else + deleteable = FALSE; + } + if (deleteable && do_lm_cb_column( ( long ) lmp, LM_CB_COL_DELETE, column, + 0, 0, 0, FALSE ) == FALSE ) + { + members = xi_get_member_list( list_obj, &nbr_members ); + xi_delete( members[column] ); + lm_set_hscroll_range( ( LM ) lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } else if (return_focus) + xi_move_focus( old_focus ); + } + if ( where.v > lmp->pix_top && where.v < lmp->pix_row1_top && + where.h >= lmp->rct.left ) + { + BOOLEAN in_hscrolling, + old_in_hscrolling; + + /* determine where to move the column, if anywhere */ + in_hscrolling = FALSE; + old_in_hscrolling = ( column >= lmp->fixed_columns ); + min_dist = INT_MAX; + position = 0; + for ( col_cnt = 0; col_cnt < lmp->nbr_columns; col_cnt++ ) + { + LM_COLUMN_DATA *column_data; + + if ( col_cnt >= lmp->fixed_columns && + col_cnt < lmp->first_vis ) + continue; + column_data = lmp->lm_column_data[col_cnt]; + temp1 = column_data->x_pix_pos; + temp2 = temp1 + 2 * col_offset + column_data->pix_width; + dist1 = abs( temp1 - where.h ); + dist2 = abs( temp2 - where.h ); + if ( dist1 < min_dist ) + { + position = col_cnt; + min_dist = dist1; + } + if ( dist2 < min_dist ) + { + position = col_cnt + 1; + min_dist = dist2; + } + if ( col_cnt == lmp->fixed_columns ) + { + if ( where.h < column_data->x_pix_pos ) + in_hscrolling = FALSE; + else + in_hscrolling = TRUE; + } + } + + /* if we need to move the column, then move it */ + if ( position < column || position > column + 1 || + position == lmp->fixed_columns ) + { + if ( column == position && position == lmp->fixed_columns && + in_hscrolling && ( !old_in_hscrolling ) ) + position -= 1; + else if ( position > column ) + position -= 1; + + /* if there is only one fixed column left, then don't move it */ + if ( column != 0 || lmp->fixed_columns != 1 ) + { + int widest_remaining, + col_width, + width_remaining, + new_fixed_width, + cnt; + BOOLEAN do_move = TRUE; + LM_COLUMN_DATA *column_data, + *cell_data2; + XinRect r; + + if ( lmp->fixed_columns < lmp->nbr_columns ) + { + /* if there is not room in the horizontal scrolling portion of + * the list for the widest column remaining in the horizontal + * scrolling portion of the list, then don't move the column */ + widest_remaining = 0; + for ( cnt = lmp->fixed_columns; cnt < lmp->nbr_columns; + ++cnt ) + { + if ( cnt == column ) + continue; + column_data = lmp->lm_column_data[cnt]; + col_width = column_data->pix_width + 2 * col_offset; + if ( col_width > widest_remaining ) + widest_remaining = col_width; + } + column_data = lmp->lm_column_data[lmp->fixed_columns]; + cell_data2 = lmp->lm_column_data[column]; + new_fixed_width = column_data->x_pix_pos; + if ( position < lmp->fixed_columns || !in_hscrolling ) + new_fixed_width += cell_data2->pix_width + 2 * col_offset; + if ( column < lmp->fixed_columns ) + new_fixed_width -= cell_data2->pix_width + 2 * col_offset; + lm_get_list_rct( lmp, &r ); + width_remaining = r.right - r.left - new_fixed_width; + if ( widest_remaining > width_remaining ) + do_move = FALSE; + } + + if ( do_move ) + { + BOOLEAN in_fixed = !in_hscrolling; + + if ( position > lmp->fixed_columns ) + in_fixed = FALSE; + if ( do_lm_cb_column( ( long ) lmp, LM_CB_COL_MOVE, column, + position, 0, 0, in_fixed ) == FALSE ) + { + members = xi_get_member_list( list_obj, &nbr_members ); + xi_move_column_internal( members[column], position, + in_hscrolling ); + lm_calc_last_vis( lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + } + } + } + } + lm_focus_cell_visible_attempt( lmp ); + break; + } + default: + break; + } +} + +/*------------------------------------------------------------------------- +function: lm_get_drag_rect +lmp: current lmp +prct: returns rectangle where row or "after-all" events will be + generated +-------------------------------------------------------------------------*/ +#define DROP_AFTER_MARGIN 10 + +static void +lm_get_drag_rect( LM_DATA * lmp, XinRect * prct ) +{ + lm_get_rect( ( LM ) lmp, LM_LIST, 0, prct ); + if ( lmp->nbr_rows == 0 || ( lmp->have_last_rec + && lmp->recs[lmp->last_fully_vis] == lmp->last_rec ) ) + { + if ( lmp->pixel_width != 0 ) + { + XinRect hsb_rct; + + xi_get_hsb_rect( lmp->list_obj, &hsb_rct ); + prct->bottom = hsb_rct.bottom; + } + else + prct->bottom += DROP_AFTER_MARGIN; + } +} + +/*------------------------------------------------------------------------- +function: lm_get_no_event_rect +lmp: current lmp +prct: returns rectangle where no drag event will be generated +-------------------------------------------------------------------------*/ +static void +lm_get_no_event_rect( LM_DATA * lmp, XinRect * prct ) +{ + lm_get_rect( ( LM ) lmp, LM_LIST, 0, prct ); + if ( lmp->list_obj->v.list->sb_win ) + { + XinRect rct; + + xi_get_sb_rect( lmp->list_obj, &rct ); + prct->right = rct.right; + } + if ( lmp->pixel_width != 0 && ( !lmp->have_last_rec + || lmp->recs[lmp->last_fully_vis] != lmp->last_rec ) ) + { + XinRect rct; + + xi_get_hsb_rect( lmp->list_obj, &rct ); + prct->bottom = rct.bottom; + } +} + +/*------------------------------------------------------------------------- +function: lm_check_interface +itf: current interface +where: current mouse position, will be translated if new interface + is returned +returns: new interface, or NULL if no change +-------------------------------------------------------------------------*/ +static XI_OBJ * +lm_check_interface( XI_OBJ * itf, XinPoint * where ) +{ + XinRect rct; + XinWindow win; + + win = xi_get_window( itf ); + XinWindowRectGet( win, &rct ); + if ( !XinRectPointContained( &rct, where ) ) + { + XinRect temp; + XinPoint pt; + XI_OBJ *new_itf; + + temp.top = temp.bottom = where->v; + temp.left = temp.right = where->h; + XinWindowRectTranslate( win, XinWindowTaskGet( ), &temp ); + pt.v = temp.top; + pt.h = temp.left; + new_itf = xi_get_itf_containing( &pt ); + if ( new_itf == itf ) + itf = NULL; + else + itf = new_itf; + if ( itf != NULL ) + { + win = xi_get_window( itf ); + XinWindowRectTranslate( XinWindowTaskGet( ), win, &temp ); + where->v = temp.top; + where->h = temp.left; + XinWindowMouseRelease( ); + XinWindowFrontSet( win ); + XinWindowPaintForce( win ); + XinWindowMouseTrap( win, TRUE ); + } + return itf; + } + return NULL; +} + +/*------------------------------------------------------------------------- +function: lm_drag_row_hit_test +lmp: current lmp +itf: current interface +where: current mouse position, will be translated if new interface + is returned +returns: new interface, or NULL if no change +-------------------------------------------------------------------------*/ +static BOOLEAN +lm_drag_row_hit_test( LM_DATA * lmp, XinPoint * where, int *rowp ) +{ + int tmp_v, + i, + first, + last; + int *pix_offsetsp; + int *pix_heightsp; + + /* figure out what row the mouse is in */ + tmp_v = where->v - lmp->mlr.top - lmp->rrr_offset; + first = max( lmp->first_fully_vis - 1, 0 ); + last = min( lmp->last_fully_vis + 1, lmp->nbr_realized_rows - 1 ); + for ( i = first, + pix_offsetsp = &lmp->pix_offsets[i], + pix_heightsp = &lmp->pix_heights[i]; + i <= last; ++i, ++pix_offsetsp, ++pix_heightsp ) + { + if ( tmp_v >= *pix_offsetsp && tmp_v < ( *pix_offsetsp + *pix_heightsp ) ) + { + *rowp = i; + break; + } + } + return ( i <= last ); +} + +/*------------------------------------------------------------------------- +function: lm_drag_row_event +itf: interface where event actually occured +lmp: current lmp +ep: xin event +oevp: orginal xin event +-------------------------------------------------------------------------*/ +void +lm_drag_row_event( XI_OBJ * itf, LM_DATA * lmp, XinEvent * ep, XinEvent * oevp ) +{ + XinPoint where; + + where = oevp->v.mouse.where; + switch ( ep->type ) + { + case XinEventMouseMove: + { + static int autoscroll_count = 0; + BOOLEAN scrolled = FALSE; + XI_OBJ *new_itf; + + if ( !lmp->dragging_row ) + { + lmp->dragging_row = TRUE; + lmp->last_itf = itf; + lmp->last_x = where.h; + lmp->org_x = lmp->last_x; + lmp->last_y = where.v; + lmp->org_y = lmp->last_y; + lmp->last_in_hscrolling = lmp->in_hscrolling; + xi_set_drag_list_obj( lmp->list_obj ); + rubber_rect( lmp ); + break; + } + new_itf = lm_check_interface( itf, &where ); + + if ( new_itf == NULL && lmp->itf_obj == itf && lmp->drag_rows_autoscroll ) + { /* Test for autoscroll */ + XinRect list_rct; + + lm_get_rect( ( LM ) lmp, LM_LIST, 0, &list_rct ); + list_rct.top = lmp->pix_row1_top; + if ( where.v > list_rct.bottom ) + { + if ( where.v > list_rct.bottom + XI_AUTOSCROLL_FAST + || ++autoscroll_count >= XI_AUTOSCROLL_COUNT ) + { + LM_SCROLL_ARG arg; + + autoscroll_count = 0; + rubber_rect( lmp ); + MEMCLEAR( arg ); + arg.lm = ( LM ) lmp; + arg.nbr_lines = 1; + arg.percent = 0; + arg.same_cell = TRUE; + arg.rec_at_top = TRUE; + lm_scroll( &arg ); + scrolled = TRUE; + } + } + else if ( where.v < list_rct.top ) + { + if ( where.v < list_rct.top - XI_AUTOSCROLL_FAST + || ++autoscroll_count >= XI_AUTOSCROLL_COUNT ) + { + LM_SCROLL_ARG arg; + + autoscroll_count = 0; + rubber_rect( lmp ); + MEMCLEAR( arg ); + arg.lm = ( LM ) lmp; + arg.nbr_lines = -1; + arg.percent = 0; + arg.same_cell = TRUE; + arg.rec_at_top = TRUE; + lm_scroll( &arg ); + scrolled = TRUE; + } + } + else + autoscroll_count = 0; + } + + if ( scrolled || where.h != lmp->last_x || where.v != lmp->last_y ) + { + if ( !scrolled ) + rubber_rect( lmp ); + if ( new_itf != NULL ) + lmp->last_itf = new_itf; + lmp->last_x = where.h; + lmp->last_y = where.v; + lmp->last_in_hscrolling = lmp->in_hscrolling; + rubber_rect( lmp ); + } + break; + } + case XinEventMouseUp: + { + int obj_num; + XI_OBJ **objlist; + XI_OBJ *dest_list; + LM_DATA *dest_lmp; + + rubber_rect( lmp ); + lmp->last_itf = NULL; + lmp->dragging_row = FALSE; + xi_set_drag_list_obj( NULL ); + + /* Check to see if window changed */ + { + XI_OBJ *new_itf; + + new_itf = lm_check_interface( itf, &where ); + if ( new_itf != NULL ) + itf = new_itf; + } + + /* Find list object in current position */ + dest_list = lmp->list_obj; + objlist = xi_get_member_list( itf, &obj_num ); + for ( ; obj_num > 0; obj_num--, objlist++ ) + if ( ( *objlist )->type == XIT_LIST ) + { + XinRect rct; + + lm_get_drag_rect( ( LM_DATA * ) ( *objlist )->v.list->lm, &rct ); + if ( XinRectPointContained( &rct, &where ) ) + { + dest_list = *objlist; + break; + } + } + dest_lmp = ( LM_DATA * ) dest_list->v.list->lm; + + /* Match coordinates to window */ + if ( dest_lmp->itf_obj != itf ) + { + XinRect temp; + + temp.top = temp.bottom = where.v; + temp.left = temp.right = where.h; + XinWindowRectTranslate( xi_get_window( itf ), xi_get_window( lmp->itf_obj ), &temp ); + where.v = temp.top; + where.h = temp.left; + } + + { /* Generate drop rows event */ + int row; + int column = 0; + LM_CB_DATA lm_cb_data; + XinRect list_rct; + + lm_cb_data.v.drop_row.src_rec = lmp->rec_being_moved; + lm_cb_data.v.drop_row.after_all_rows = FALSE; + lm_cb_data.v.drop_row.delete_row = FALSE; + lm_cb_data.rec = 0; + lm_get_drag_rect( dest_lmp, &list_rct ); + if ( !XinRectPointContained( &list_rct, &where ) ) + { + lm_get_no_event_rect( dest_lmp, &list_rct ); + if ( XinRectPointContained( &list_rct, &where ) ) + break; + row = column = 0; + lm_cb_data.v.drop_row.delete_row = TRUE; + } + else + { + if ( where.v < dest_lmp->pix_row1_top ) + break; + if ( lm_drag_row_hit_test( dest_lmp, &where, &row ) ) + lm_cb_data.rec = dest_lmp->recs[row]; + else + lm_cb_data.v.drop_row.after_all_rows = TRUE; + } + lm_cb_data.lm = ( LM ) dest_lmp; + lm_cb_data.cb_type = LM_CB_DROP_ROW; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) row; + lm_cb_data.column = ( unsigned char ) column; + lm_cb_data.v.drop_row.shift = ep->v.mouse.shift; + lm_cb_data.v.drop_row.control = ep->v.mouse.control; + lm_cb_data.v.drop_row.src_list = lmp->list_obj; + ( *lmp->lm_cb ) ( &lm_cb_data ); + } + break; + } + default: + break; + } +} + +/*------------------------------------------------------------------------- +function: calc_x +lmp: current lmp +ep: xvt event +returns: Calculates and returns the X pixel position of the rubber band line. + Used only when sizing columns. +-------------------------------------------------------------------------*/ +static int +calc_x( LM_DATA * lmp, XinEvent * ep ) +{ + int column = lmp->column_being_sized; + int temp, + temp2, + widest_remaining; + int min_width_in_pix = 16; + int col_offset; + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + + /* temp is the min width position of the column, relative to the left edge of + * the list. */ + temp = lmp->lm_column_data[column]->x_pix_pos + col_offset + + min_width_in_pix; + if ( lmp->lm_column_data[column]->wrap_text_scrollbar ) + temp += (int)XinMetricGet( XinMetricVerticalScrollBarWidth ); + temp = max( ep->v.mouse.where.h, temp ); + widest_remaining = 0; + if ( lmp->pixel_width ) + { + int col_offset, + col_width, + cnt; + LM_COLUMN_DATA *column_data; + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + if ( column < lmp->fixed_columns ) + { + /* figure out the widest column in the horizontal scrolling portion of + * the list */ + for ( cnt = lmp->fixed_columns; cnt < lmp->nbr_columns; ++cnt ) + { + column_data = lmp->lm_column_data[cnt]; + col_width = column_data->pix_width + 2 * col_offset; + if ( col_width > widest_remaining ) + widest_remaining = col_width; + } + /* add the widths of all of the columns to the right of this column in + * the fixed portion of the list */ + temp2 = 0; + for ( cnt = column + 1; cnt < lmp->fixed_columns; ++cnt ) + { + column_data = lmp->lm_column_data[cnt]; + col_width = column_data->pix_width + 2 * col_offset; + temp2 += col_width; + } + temp = min( ( lmp->pixel_width - widest_remaining - temp2 ) - BORDER_WIDTH, + temp ); + } + else + temp = min( ( lmp->pixel_width + lmp->delta_x ) - BORDER_WIDTH, temp ); + } + return temp; +} + + +/*------------------------------------------------------------------------- +function: rubber_x +lmp: current lmp +x: draw a rubber line at position x +-------------------------------------------------------------------------*/ +static void +rubber_x( LM_DATA * lmp, int x ) +{ +#if XIWS != XIWS_WM + int top, + bottom; + XinDrawTools new_ctools; + XinPoint pnt; + XinWindow win = lmp->win; + + top = lmp->pix_top; + bottom = lmp->mlr.bottom; + XinWindowDrawToolsNormalGet( &new_ctools ); + XinWindowDrawToolsSet( win, &new_ctools ); + XinWindowPenSet( win, &rubber_cpen ); + XinWindowDrawModeSet( win, XinDrawModeXor ); + xi_set_clip( win, NULL ); + pnt.h = x; + pnt.v = top; + if ( !lmp->down_in_hscrolling ) + pnt.h += lmp->rct.left; + lm_move_to( lmp, pnt, FALSE, lmp->down_in_hscrolling ); + pnt.v = bottom; + lm_draw_line( lmp, pnt, FALSE, lmp->down_in_hscrolling ); +#else + NOREF( lmp ); + NOREF( x ); +#endif +} + + +/*------------------------------------------------------------------------- +function: lm_size_event +lmp: current lmp +ep: xvt event +-------------------------------------------------------------------------*/ +void +lm_size_event( LM_DATA * lmp, XinEvent * ep ) +{ + int x; + + switch ( ep->type ) + { + case XinEventMouseDown: + case XinEventMouseDouble: + x = calc_x( lmp, ep ); + lmp->last_x = x; + rubber_x( lmp, x ); + break; + case XinEventMouseMove: + x = calc_x( lmp, ep ); + rubber_x( lmp, lmp->last_x ); + lmp->last_x = x; + rubber_x( lmp, x ); + break; + case XinEventMouseUp: + { + int col_offset; + int column; + int temp; + int width_in_chars; + int pixel_width; + XI_OBJ *list_obj, + **members; + int nbr_members; + int char_width; + LM_COLUMN_DATA *lm_column_data; + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + x = calc_x( lmp, ep ); + rubber_x( lmp, lmp->last_x ); + column = lmp->column_being_sized; + lm_column_data = lmp->lm_column_data[column]; + temp = lm_column_data->x_pix_pos + col_offset; + pixel_width = ( x - temp ) - col_offset; + width_in_chars = ( int ) ( pixel_width / ( long ) xi_get_fu_width( lmp->itf_obj ) ); + list_obj = lmp->list_obj; + + char_width = width_in_chars * XI_FU_MULTIPLE; + if ( xi_get_xil_pref( list_obj->itf ) ) + char_width = width_in_chars; + + if ( do_lm_cb_column( ( long ) lmp, LM_CB_COL_SIZE, column, + 0, char_width, pixel_width, FALSE ) == FALSE ) + { + int i; + + members = xi_get_member_list( list_obj, &nbr_members ); + xi_column_set_pixel_width( members[column], pixel_width ); + i = lm_get_left_most_far_right_col( lmp, lmp->nbr_columns ); + if ( i < lmp->first_vis ) + { + XinWindowPaintForce( lmp->win ); + lm_hscroll( ( LM ) lmp, lmp->first_vis - i, 0 ); + } + else + { + lm_calc_last_vis( lmp ); + lm_set_hscroll_bar( ( LM ) lmp ); + } + } + lm_focus_cell_visible_attempt( lmp ); + break; + } + default: + break; + } +} + + +/*------------------------------------------------------------------------- +function: lm_set_bitmap +lm: current lm +bitmap: bitmap object +row: +column: +-------------------------------------------------------------------------*/ +void +lm_set_bitmap( LM lm, XI_BITMAP* bitmap, int row, int column ) +{ + LM_DATA *lmp = LMP( lm ); + + lmp->cell_data[row][column].bitmap = xi_bitmap_copy( bitmap ); + if ( LMP( lm )->attrib & XI_ATR_VISIBLE ) + redraw_cell( lm, row, column, FALSE ); +} + + +/*------------------------------------------------------------------------- +function: lm_set_icon +lm: current lm +icon_rid: icon resource id +row: +column: +-------------------------------------------------------------------------*/ +void +lm_set_icon( LM lm, int icon_rid, int row, int column ) +{ + LM_DATA *lmp = LMP( lm ); + + lmp->cell_data[row][column].icon_rid = icon_rid; + if ( LMP( lm )->attrib & XI_ATR_VISIBLE ) + redraw_cell( lm, row, column, FALSE ); +} + + +/*------------------------------------------------------------------------- +function: lm_set_column_bitmap +lm: current lm +bitmap: bitmap object +cid: cid of the column to set +-------------------------------------------------------------------------*/ +void +lm_set_column_bitmap( LM lm, XI_BITMAP* bitmap, int cid ) +{ + LM_DATA *lmp = LMP( lm ); + XI_OBJ *list = lmp->list_obj; + int column; + + for ( column = 0; column < list->nbr_children; column++ ) + { + if ( list->children[column]->cid == cid ) + { + XinRect rect; + + lmp->lm_column_data[column]->bitmap = xi_bitmap_copy( bitmap ); + lm_get_rect( lm, LM_COLUMN, column, &rect ); + xi_invalidate_rect( lmp->win, &rect ); + break; + } + } +} + + +/*------------------------------------------------------------------------- +function: lm_set_column_icon +lm: current lm +icon_rid: icon resource id +cid: cid of the column to set +-------------------------------------------------------------------------*/ +void +lm_set_column_icon( LM lm, int icon_rid, int cid ) +{ + LM_DATA *lmp = LMP( lm ); + XI_OBJ *list = lmp->list_obj; + int column; + + for ( column = 0; column < list->nbr_children; column++ ) + { + if ( list->children[column]->cid == cid ) + { + XinRect rect; + + lmp->lm_column_data[column]->icon_rid = icon_rid; + lm_get_rect( lm, LM_COLUMN, column, &rect ); + xi_invalidate_rect( lmp->win, &rect ); + break; + } + } +} + + +/*------------------------------------------------------------------------- +function: lm_set_sel +lm: current lm +row: row +column: column +c1: starting position in selection +c2: ending position +-------------------------------------------------------------------------*/ +void +lm_set_sel( LM lm, int row, int column, BOOLEAN v_scrolled, int c1, int c2 ) +{ + LM_DATA *lmp = LMP( lm ); + + if ( !lm_focus_list_has( lmp ) ) + { + lm_focus_cell_set( lmp, row, column, FALSE ); + } + else + { + int focus_row, + focus_column; + BOOLEAN is_v_scrolled; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &is_v_scrolled ); + if ( focus_row != row || focus_column != column || v_scrolled != is_v_scrolled ) + lm_focus_cell_set( lmp, row, column, FALSE ); + } + if ( v_scrolled ) + { + lm_focus_cell_selection_set( lmp, c1, c2 ); + } + else + { + XI_TEXT *text; + + text = xi_text_focus_get( lmp->win ); + if ( text ) + xi_text_selection_set( text, c1, c2 ); + } +} + +/*------------------------------------------------------------------------- +function: scroll_list +lmp: current lmp +left_col: +right_col: +-------------------------------------------------------------------------*/ +static void +scroll_list( LM_DATA * lmp, int new_first_col ) +{ + XinRect r; + int new_pos; + int dist; + + new_pos = lmp->lm_column_data[new_first_col]->x_pix_pos + - lmp->lm_column_data[lmp->fixed_columns]->x_pix_pos; + if ( new_pos == lmp->delta_x ) + { + if ( lmp->nbr_columns == lmp->fixed_columns ) + lmp->delta_x = 0; + return; + } + dist = new_pos - lmp->delta_x; + lmp->delta_x += dist; + r.left = lmp->vir_left; + r.right = lmp->vir_right; +#if XIWS != XIWS_WM + r.top = lmp->rct.top + BORDER_WIDTH; + r.bottom = lmp->rct.bottom - BORDER_WIDTH; +#else + r.top = lmp->rct.top; + r.bottom = lmp->rct.bottom; +#endif + if ( !lmp->itf_obj->v.itf->half_baked ) + XinWindowPaintForce( lmp->win ); + xi_set_update_obj( lmp->list_obj ); + lmp->last_vis = lmp->first_vis; + lm_calc_last_vis( lmp ); + xi_scroll_rect( lmp->win, &r, -dist, 0 ); + + if ( !lmp->itf_obj->v.itf->half_baked ) + XinWindowPaintForce( lmp->win ); + lm_set_hscroll_bar( ( LM ) lmp ); +} + + +/*------------------------------------------------------------------------- +function: lm_hscroll +lm: current lm +nbr_columns: number of columns to scroll +pos: if set, pos is a percentage based on where the thumb was dropped. +-------------------------------------------------------------------------*/ +void +lm_hscroll( LM lm, int nbr_columns, int pos ) +{ + LM_DATA *lmp = LMP( lm ); + int last_vis, + lmfrc, + starting_column; + + XinWindowPaintForce( lmp->win ); + if ( lmp->nbr_columns == 0 ) + return; + lmfrc = lm_get_left_most_far_right_col( LMP( lm ), lmp->nbr_columns ); + last_vis = min( lmp->last_vis, lmp->nbr_columns - 1 ); + if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + lm_focus_cell_invis_make( lmp ); + else + { + if ( !lmp->itf_obj->v.itf->moving_focus ) + if ( !xi_move_focus( lmp->itf_obj ) ) + return; + } + if ( nbr_columns == XI_SCROLL_FIRST ) + { + starting_column = lmfrc; + if ( starting_column ) + { + starting_column = starting_column - lmp->fixed_columns; + starting_column = ( int ) ( ( ( long ) pos * ( long ) starting_column ) / + ( long ) 100 ); + } + starting_column += lmp->fixed_columns; + lmp->first_vis = starting_column; + lmp->first_vis = min( lmp->first_vis, lmp->nbr_columns - 1 ); + scroll_list( lmp, lmp->first_vis ); + lm_focus_cell_visible_attempt( lmp ); + return; + } + if ( nbr_columns == XI_SCROLL_PGDOWN ) + { + starting_column = min( last_vis + 1, lmfrc ); + starting_column = min( starting_column, lmp->nbr_columns - 1 ); + lmp->first_vis = starting_column; + lmp->first_vis = min( lmp->first_vis, lmp->nbr_columns - 1 ); + scroll_list( lmp, lmp->first_vis ); + lm_focus_cell_visible_attempt( lmp ); + return; + } + if ( nbr_columns == XI_SCROLL_PGUP ) + { + starting_column = lm_get_left_most_far_right_col( lmp, lmp->first_vis ); + starting_column = min( starting_column, lmp->nbr_columns - 1 ); + lmp->first_vis = starting_column; + lmp->first_vis = min( lmp->first_vis, lmp->nbr_columns - 1 ); + scroll_list( lmp, lmp->first_vis ); + lm_focus_cell_visible_attempt( lmp ); + return; + } + lmp->first_vis += nbr_columns; + if ( nbr_columns > 0 ) + { + lmp->first_vis = min( lmp->first_vis, lm_get_left_most_far_right_col( lmp, lmp->nbr_columns ) ); + lmp->first_vis = min( lmp->first_vis, lmp->nbr_columns - 1 ); + } + else + { + lmp->first_vis = max( lmp->first_vis, lmp->fixed_columns ); + lmp->first_vis = min( lmp->first_vis, lmp->nbr_columns - 1 ); + } + scroll_list( lmp, lmp->first_vis ); + lm_focus_cell_visible_attempt( lmp ); +} + +void +lm_calculate_pix_offsets( LM lm ) +{ + LM_DATA *lmp = LMP( lm ); + + calculate_pix_offsets( lmp, TRUE ); + lm_make_rrr_room_pix( lmp, 0, FALSE ); +} + +BOOLEAN +lm_cr_is_ok( LM lm, int row, int col, BOOLEAN v_scrolled ) +{ + LM_DATA *lmp = LMP( lm ); + LM_COLUMN_DATA *lm_column_data; + LM_CELL_DATA *cell_data; + + lm_column_data = lmp->lm_column_data[col]; + if ( lm_column_data->cr_ok ) + return TRUE; + if ( v_scrolled ) + { + if ( lm_focus_cell_is_button_full_cell( lmp ) ) + return TRUE; + else + return FALSE; + } + cell_data = &lmp->cell_data[row][col]; + if ( cell_data->button_full_cell ) + return TRUE; + else + return FALSE; +} + +BOOLEAN +lm_is_button_full_cell( LM lm, int row, int col ) +{ + LM_DATA *lmp = LMP( lm ); + LM_CELL_DATA *cell_data = &lmp->cell_data[row][col]; + + return cell_data->button_full_cell; +} + +void +lm_set_rect( LM lm, XinRect *rect ) +{ + LM_DATA *lmp; + XinRect fu_rect; + + lmp = (LM_DATA*)lm; + + fu_rect = *rect; + fu_rect.right -= 2 * BORDER_WIDTH; + if (lmp->list_obj->v.list->hsb_win) + { + XinRect hsb_rect; + xi_get_hsb_rect( lmp->list_obj, & hsb_rect ); + fu_rect.bottom += hsb_rect.bottom - hsb_rect.top; + } + lmp->nbr_rows = (fu_rect.bottom - fu_rect.top) / lmp->pix_row_spacing; + xi_pu_to_fu( lmp->itf_obj, (XinPoint*)&fu_rect, 2 ); + lmp->list_obj->v.list->xi_pnt = *(XinPoint*)&fu_rect; + if (lmp->list_obj->v.list->height != 0) + lmp->list_obj->v.list->height = fu_rect.bottom - fu_rect.top; + if (lmp->list_obj->v.list->width != 0 ) + lmp->list_obj->v.list->width = fu_rect.right - fu_rect.left; + + /* TODO - lm_recalc_metrics gets the proper height for the list not including + the hsb, then puts the hsb inside that rect instead of below it. Therefore, + the first time you resize, the list gets shorter by a scrollbar height, and + thereafter it doesn't change. */ + lm_recalc_metrics( lm ); + +} diff --git a/src/xi01/xilm3.c b/src/xi01/xilm3.c new file mode 100644 index 000000000..41acf4d55 --- /dev/null +++ b/src/xi01/xilm3.c @@ -0,0 +1,4899 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#include "xi.h" +#include "xitext.h" +#include "xilm.h" +#include "xilmst.h" +#include "xiutils.h" +#include "xidisply.h" +#include + +static XinDrawTools lm_normal_ctools; + +#define LM_COL_ATTR(lm, col) (LMP(lm)->lm_column_data[col]->attrib) +#define LM_REDRAW_COL_ATR (LM_COL_ATR_ENABLED | LM_COL_ATR_RJUST | LM_COL_ATR_PASSWORD | LM_COL_ATR_SELECTED) +#define LM_REDRAW_ROW_ATR (LM_ROW_ATR_ENABLED | LM_ROW_ATR_SELECTED) + +#define LM_REDRAW_CELL_ATR (LM_CELL_ATR_SELECTED | LM_CELL_ATR_RJUST | LM_CELL_ATR_HCENTER) +#define SELECT_CELLS_OFFSET 1 + +typedef struct +{ + BOOLEAN XinWindowPaintNeeds; + XinRect rct; + XinRect prct; +} ROW_INFO; + +static XinBrush lm_white_cbrush; +static XinPen lm_black_cpen; +static BOOLEAN lm_tools_inited = FALSE; + +/*------------------------------------------------------------------------- +function: lm_draw_clipped_text +lmp: current lmp +s: string +bound_rctp: +clip_rctp: +attrib: +set_the_cpen: +-------------------------------------------------------------------------*/ +static void +lm_draw_clipped_text( LM_DATA * lmp, char *s, XinRect * bound_rctp, + XinRect * clip_rctp, unsigned long attrib, BOOLEAN set_the_cpen, + BOOLEAN adj_v ) +{ + XinRect br, + cr; + BOOLEAN left, + right; + + br = *bound_rctp; + br.left += lmp->rct.left; + br.right += lmp->rct.left; + + if ( adj_v ) + { + lm_adj_v( lmp, br.top ); + lm_adj_v( lmp, br.bottom ); + } + + left = lm_adj_h( lmp, &br.left ); + right = lm_adj_h( lmp, &br.right ); + if ( !left && !right ) + return; + xi_rect_intersect( &cr, &br, clip_rctp ); + xi_draw_clipped_text( lmp->win, lmp->cur_font, s, &br, &cr, attrib, + set_the_cpen, 0, -1, '\0', 0, NULL ); +} + +/*------------------------------------------------------------------------- +function: lm_draw_rect +lmp: current lmp +rctp: rectangle to draw +-------------------------------------------------------------------------*/ +static void +lm_draw_rect( LM_DATA * lmp, XinRect * rctp, BOOLEAN adj_v ) +{ + XinRect r; + BOOLEAN leftb, + rightb; + + r = *rctp; + r.left += lmp->rct.left; + if ( r.right != SHRT_MAX ) + r.right += lmp->rct.left; + + if ( adj_v ) + { + lm_adj_v( lmp, r.top ); + lm_adj_v( lmp, r.bottom ); + } + + leftb = lm_adj_h( lmp, &r.left ); + if ( r.right == SHRT_MAX ) + rightb = TRUE; + else + rightb = lm_adj_h( lmp, &r.right ); + if ( !leftb && !rightb ) + return; + xi_draw_rect( lmp->win, &r ); +} + + +/*------------------------------------------------------------------------- +function: lm_draw_icon +lmp: current lmp +left: h position +top: v position +icon_rid: resource id +vir_clip: virtual clip rectangle +phys_rct: +fore_color: desired colors if icons +back_color: +-------------------------------------------------------------------------*/ +static void +lm_draw_icon( LM_DATA * lmp, int left, int top, int icon_rid, XI_BITMAP * bitmap, + XinRect * vir_clip, XinRect * phys_rct, BOOLEAN adj_v, + XinColor fore_color, XinColor back_color ) +{ + XinRect crct, + r; + short sleft; + BOOLEAN leftb, + rightb; + + left += lmp->rct.left; + r = *phys_rct; + + r.left += lmp->rct.left; + r.right += lmp->rct.left; + + if ( adj_v ) + { + lm_adj_v( lmp, r.top ); + lm_adj_v( lmp, r.bottom ); + } + + leftb = lm_adj_h( lmp, &r.left ); + rightb = lm_adj_h( lmp, &r.right ); + if ( !leftb && !rightb ) + return; + if ( adj_v ) + lm_adj_v( lmp, top ); + if ( xi_rect_intersect( &crct, &r, vir_clip ) ) + { + xi_set_clip( lmp->win, &crct ); + sleft = left; + if ( lm_adj_h( lmp, &sleft ) ) + { + if ( bitmap != NULL ) + xi_bitmap_draw( bitmap, lmp->win, &r, &crct, FALSE ); + else + xi_draw_icon( lmp->win, sleft, top, icon_rid, fore_color, back_color ); + } + } +} + +/*------------------------------------------------------------------------- +function: lm_draw_3d_rect +lmp: current lmp +rctp: rectangle +well: or platform +depth: in pixels +-------------------------------------------------------------------------*/ +static void +lm_draw_3d_rect( LM_DATA * lmp, XinRect * rctp, BOOLEAN well, int depth, BOOLEAN adj_v ) +{ + XinRect r; + BOOLEAN left, right; + const XinColor color_light = aga_get_pref(AGA_PREF_BTN_COLOR_LIGHT); + const XinColor color_ctrl = aga_get_pref(AGA_PREF_BTN_COLOR_CTRL); + const XinColor color_dark = aga_get_pref(AGA_PREF_BTN_COLOR_DARK); + + r = *rctp; + + r.left += lmp->rct.left; + r.right += lmp->rct.left; + + if ( adj_v ) + { + lm_adj_v( lmp, r.top ); + lm_adj_v( lmp, r.bottom ); + } + + left = lm_adj_h( lmp, &r.left ); + right = lm_adj_h( lmp, &r.right ); + if ( !left && !right ) + return; + + if ( xi_get_pref( XI_PREF_3D_LOOK ) ) + xi_draw_shaded_rect( lmp->win, &r, well, depth, color_light, color_ctrl, color_dark); + else + xi_draw_3d_rect( lmp->win, &r, well, depth, color_light, color_ctrl, color_dark); +} + +/*********** draw column headings ***********/ +static void +draw_column_headings( LM_DATA * lmp, XinRect * actual_rct ) +{ + XinWindow win = lmp->win; + LM lm = ( LM ) lmp; + XinRect clip_rct; + + clip_rct = *actual_rct; + if ( !lmp->update_cells_only ) + { + if ( !( lmp->update_rows_at_top + lmp->update_rows_at_bottom ) ) + { + if ( !lmp->no_heading ) + { + int col; + + if ( lmp->nbr_columns == 0 ) + { + XinRect hr; + XinBrush cb; + + hr.top = lmp->pix_top + BORDER_WIDTH; + hr.bottom = lmp->pix_hdr_bottom + BORDER_WIDTH; + hr.left = lmp->rct.left; + hr.right = lmp->rct.right; + XinWindowPenSet( win, &hollow_cpen ); + cb = white_cbrush; + cb.fore_color = lmp->white_space_color; + XinWindowBrushSet( win, &cb ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + xi_set_clip( win, actual_rct ); + xi_draw_rect( win, &hr ); + } + for ( col = 0; col < lmp->nbr_columns; col++ ) + { + XinRect heading_rct, + cell_rct; + LM_COLUMN_DATA *col_data; + unsigned long attrib; + + col_data = lmp->lm_column_data[col]; + if ( col_data->suppress_update_heading ) + continue; + + lm_get_cell_rect( &heading_rct, lm, 1, col, FALSE, FALSE ); + heading_rct.top = lmp->pix_top + BORDER_WIDTH; +#if XIWS == XIWS_WM + heading_rct.bottom = lmp->pix_hdr_bottom - VPIX_PER_CH; + lm_get_cell_rect( &cell_rct, lm, 1, col, TRUE, FALSE ); + cell_rct.top = lmp->rct.top + VPIX_PER_CH; +#else + heading_rct.bottom = lmp->pix_hdr_bottom; + lm_get_cell_rect( &cell_rct, lm, 1, col, TRUE, FALSE ); + cell_rct.top = lmp->rct.top + 2 * BORDER_WIDTH; +#endif + cell_rct.bottom = lmp->pix_hdr_bottom; + XinWindowPenSet( win, &hollow_cpen ); + XinWindowBrushSet( win, &white_cbrush ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + xi_set_clip( win, actual_rct ); + if ( col_data->font ) + lmp->cur_font = col_data->font; + else + lmp->cur_font = lmp->font; + + if ( col_data->heading_well || col_data->heading_platform ) + { + XinColor fore_color, + back_color; + + lm_draw_3d_rect( lmp, &heading_rct, + ( BOOLEAN ) ( COLUMN_IS_SELECTED( lm, col ) + || COLUMN_IS_PUSHED( lm, col ) ? + !col_data->heading_well : + col_data->heading_well ), + 2, FALSE ); + /* Adjust for exact drawable area */ + cell_rct.left++; + cell_rct.right--; + cell_rct.top++; + cell_rct.bottom = heading_rct.bottom - 2 + BORDER_WIDTH; + /* Reimplemented below 10/05/2012 + if ( COLUMN_IS_ENABLED( lm, col ) ) + { + if ( LIST_IS_ENABLED( lmp ) ) + fore_color = lmp->enabled_color; + else + fore_color = lmp->disabled_color; + back_color = lmp->back_color; + } + else + { + fore_color = lmp->disabled_color; + back_color = lmp->disabled_back_color; + } + */ + if ( col_data->heading_well || col_data->heading_platform ) // Alway true ??? + { + fore_color = aga_get_pref(AGA_PREF_BTN_COLOR_TEXT); + back_color = aga_get_pref(AGA_PREF_BTN_COLOR_CTRL); + } + XinWindowColorTextForeSet( win, fore_color ); + XinWindowColorTextBackSet( win, back_color ); + } + else + { + XinColor fore_color; + + if ( COLUMN_IS_ENABLED( lm, col ) ) + { + if ( LIST_IS_ENABLED( lmp ) ) + fore_color = lmp->enabled_color; + else + fore_color = lmp->disabled_color; + XinWindowColorTextForeSet( win, fore_color ); + XinWindowColorTextBackSet( win, lmp->back_color ); + } + else + { + fore_color = lmp->disabled_color; + XinWindowColorTextForeSet( win, fore_color ); + XinWindowColorTextBackSet( win, lmp->disabled_back_color ); + } + if ( COLUMN_IS_SELECTED( lm, col ) ) + { + XinBrush cb; + + cb = white_cbrush; + cb.fore_color = fore_color; + XinWindowBrushSet( win, &cb ); + XinWindowColorTextForeSet( win, XI_COLOR_WHITE ); + } + lm_draw_rect( lmp, &heading_rct, FALSE ); + /* Adjust for exact drawable area */ + cell_rct.left--; + cell_rct.right++; + cell_rct.top--; + cell_rct.bottom++; + } + attrib = ( ( LM_COL_ATTR( lm, col ) | XI_ATR_VISIBLE ) & + ~XI_ATR_PASSWORD ) | + ( lmp->min_heading_height ? XI_ATR_VCENTER : 0 ); + if ( col_data->center_heading ) + { + attrib |= XI_ATR_HCENTER; + attrib &= ~XI_ATR_RJUST; + } + clip_rct.top = cell_rct.top; + clip_rct.bottom = cell_rct.bottom; + if ( col_data->icon_mode == XIM_ICON_HAS_PRIORITY + || col_data->icon_mode == XIM_TEXT_AND_BITMAP_OVERLAP ) + { + if ( col_data->icon_rid || col_data->bitmap != NULL ) + { + XinColor fore_color, + back_color; + + if ( COLUMN_IS_ENABLED( lm, col ) ) + { + if ( LIST_IS_ENABLED( lmp ) ) + fore_color = lmp->enabled_color; + else + fore_color = lmp->disabled_color; + back_color = lmp->back_color; + } + else + { + fore_color = lmp->disabled_color; + back_color = lmp->disabled_back_color; + } + if ( col_data->heading_well || col_data->heading_platform ) + back_color = aga_get_pref(AGA_PREF_BTN_COLOR_CTRL); + { + XinRect temp_rct = cell_rct; + + temp_rct.top--; + temp_rct.left--; + temp_rct.right++; + temp_rct.bottom--; + if ( col_data->heading_well || col_data->heading_platform ) + temp_rct.bottom--; + clip_rct.top--; + lm_draw_icon( lmp, temp_rct.left + col_data->icon_x, + temp_rct.top + col_data->icon_y, col_data->icon_rid, + col_data->bitmap, &clip_rct, &temp_rct, FALSE, + fore_color, back_color ); + clip_rct.top++; + } + } + if ( col_data->icon_mode == XIM_TEXT_AND_BITMAP_OVERLAP + || ( col_data->icon_rid == 0 && col_data->bitmap == NULL ) ) + { + char *ch; + int lines; + + ch = col_data->heading_text; + lines = 1; + while ( *ch != '\0' ) + { + if ( *ch == '\n' ) + ++lines; + ++ch; + } + XinWindowTextOpaqueSet( lmp->win, FALSE ); + if ( lines == 1 ) + { + lm_draw_clipped_text( lmp, col_data->heading_text, &cell_rct, + &clip_rct, + attrib, TRUE, FALSE ); + } + else + { + char *s; + char *first_char; + char *ch; + BOOLEAN bk = FALSE; + int leading, + ascent, + descent; + + s = (char*)XinMemoryAlloc( strlen( col_data->heading_text ) + 1 ); + strcpy( s, col_data->heading_text ); + ch = s; + first_char = ch; + XinFontMetricsGet( lmp->cur_font, &leading, &ascent, &descent ); + cell_rct.top += + ( cell_rct.bottom - cell_rct.top - + ( leading + ascent + descent ) * lines ) / 2; + cell_rct.bottom = cell_rct.top + leading + ascent + descent; + while ( TRUE ) + { + while ( *ch != '\n' && *ch != '\0' ) + ++ch; + if ( *ch == '\0' ) + bk = TRUE; + *ch = 0; + lm_draw_clipped_text( lmp, first_char, &cell_rct, + &clip_rct, + attrib & ~XI_ATR_VCENTER, TRUE, FALSE ); + if ( bk ) + break; + cell_rct.top += ( leading + ascent + descent ); + cell_rct.bottom += ( leading + ascent + descent ); + ++ch; + first_char = ch; + } + XinMemoryFree( s ); + } + } + } + if ( col_data->icon_mode == XIM_TEXT_WITH_ICON_ON_LEFT + || col_data->icon_mode == XIM_TEXT_WITH_ICON_ON_RIGHT ) + { /* Draw both text and icon, even if the icon is + * currently zero. */ + XinColor fore_color, + back_color; + char *ch; + int lines; + short bitmap_width; + short bitmap_height; + + if ( col_data->icon_rid || col_data->bitmap != NULL ) + { + if ( col_data->bitmap != NULL ) + xi_bitmap_size_get( col_data->bitmap, &bitmap_width, &bitmap_height ); + if ( COLUMN_IS_ENABLED( lm, col ) ) + { + if ( LIST_IS_ENABLED( lmp ) ) + fore_color = lmp->enabled_color; + else + fore_color = lmp->disabled_color; + back_color = lmp->back_color; + } + else + { + fore_color = lmp->disabled_color; + back_color = lmp->disabled_back_color; + } + if ( col_data->heading_well || col_data->heading_platform ) + back_color = xi_get_pref( XI_PREF_COLOR_CTRL ); + { + XinRect temp_rct = cell_rct; + + if ( col_data->icon_mode == XIM_TEXT_WITH_ICON_ON_LEFT ) + { + temp_rct.left = cell_rct.left - 1; + if ( col_data->bitmap != NULL ) + temp_rct.right = temp_rct.left + bitmap_width; + } + else + { + if ( col_data->bitmap != NULL ) + { + temp_rct.left = cell_rct.right - bitmap_width; + temp_rct.right = temp_rct.left + bitmap_width; + } + else + temp_rct.left = cell_rct.right - (short)XinMetricGet(XinMetricIconWidth); + if ( temp_rct.left < cell_rct.left - 1 ) + temp_rct.left = cell_rct.left - 1; + } + temp_rct.top--; + temp_rct.bottom--; + if ( col_data->heading_well || col_data->heading_platform ) + temp_rct.bottom--; + clip_rct.top--; + lm_draw_icon( lmp, temp_rct.left, temp_rct.top, col_data->icon_rid, + col_data->bitmap, &clip_rct, &temp_rct, FALSE, + fore_color, back_color ); + clip_rct.top++; + } + } + if ( col_data->icon_mode == XIM_TEXT_WITH_ICON_ON_LEFT ) + { + if ( col_data->bitmap != NULL ) + cell_rct.left += bitmap_width; + else + cell_rct.left += (short)XinMetricGet(XinMetricIconWidth); + if ( cell_rct.left > cell_rct.right ) + cell_rct.left = cell_rct.right; + } + else + { + if ( col_data->bitmap != NULL ) + cell_rct.right -= bitmap_width; + else + cell_rct.right -= (short)XinMetricGet(XinMetricIconWidth); + if ( cell_rct.right < cell_rct.left ) + cell_rct.right = cell_rct.left; + } + ch = col_data->heading_text; + lines = 1; + while ( *ch != '\0' ) + { + if ( *ch == '\n' ) + ++lines; + ++ch; + } + XinWindowTextOpaqueSet( lmp->win, FALSE ); + if ( lines == 1 ) + { + lm_draw_clipped_text( lmp, col_data->heading_text, &cell_rct, + &clip_rct, + attrib, TRUE, FALSE ); + } + else + { + char *s; + char *first_char; + char *ch; + BOOLEAN bk = FALSE; + int leading, + ascent, + descent; + + s = XinMemoryAlloc( strlen( col_data->heading_text ) + 1 ); + strcpy( s, col_data->heading_text ); + ch = s; + first_char = ch; + XinFontMetricsGet( lmp->cur_font, &leading, &ascent, &descent ); + cell_rct.top += + ( cell_rct.bottom - cell_rct.top - + ( leading + ascent + descent ) * lines ) / 2; + cell_rct.bottom = cell_rct.top + leading + ascent + descent; + while ( TRUE ) + { + while ( *ch != '\n' && *ch != '\0' ) + ++ch; + if ( *ch == '\0' ) + bk = TRUE; + *ch = 0; + lm_draw_clipped_text( lmp, first_char, &cell_rct, + &clip_rct, + attrib & ~XI_ATR_VCENTER, TRUE, FALSE ); + if ( bk ) + break; + cell_rct.top += ( leading + ascent + descent ); + cell_rct.bottom += ( leading + ascent + descent ); + ++ch; + first_char = ch; + } + XinMemoryFree( s ); + } + } + } + } + } + } +} + + +/*********** draw cells ***********/ +static void +draw_cells( LM_DATA * lmp, BOOLEAN update ) +{ + int first_row; + int last_row; + + first_row = lmp->first_fully_vis; + if ( first_row < 0 ) + first_row = 0; + last_row = min( lmp->last_fully_vis + 1, lmp->nbr_realized_rows - 1 ); + if ( last_row < 0 ) + return; + draw_cell_range( lmp, first_row, last_row, 0, lmp->nbr_columns - 1, update ); +} + +/*-------------------------------------------------------------------------*/ +/* draw_other_rectangles */ +/*-------------------------------------------------------------------------*/ +static void +draw_other_rectangles( LM_DATA * lmp, XinRect * actual_rct ) +{ + XinWindow win = lmp->win; + XinRect lmp_rct, + vr, + hr; + int i, + actual_r, + hrule_h; + XinBrush cbrush; + XI_LIST_DATA *list_data; + XI_OBJ *list_obj; + + lmp_rct = lmp->rct; + if ( lmp->pixel_width ) + actual_r = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH; + else + actual_r = lmp->rct.right; + list_obj = lmp->list_obj; + list_data = list_obj->v.list; + hrule_h = actual_r; + + /*********** Graphical: border at right of last column ***********/ + /*********** Graphical: rectangle around entire list ***********/ + /*********** Graphical: rectangle at bottom of list ***********/ + /* NOTE: GRAPHICAL SYSTEMS ONLY, HERE. CH is in beginning of draw_lm */ +#if XIWS != XIWS_WM + xi_set_clip( win, actual_rct ); + XinWindowPenSet( win, &black_cpen ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + if ( lmp->pixel_width ) + { + XinPoint p, + p2; + int width; + + p.h = lmp->rct.right - 1 - lmp->rct.left; + p.v = lmp_rct.top; + p2 = p; + p2.v = min( lmp_rct.bottom, lmp->rrr_bottom + lmp->rrr_offset + lmp->mlr.top ); + width = BORDER_WIDTH; + XinWindowPenSet( win, &black_cpen ); + if ( !lmp->no_vert_lines && lmp->nbr_columns != 0 ) + { /* Only draw this line if there are actually + * columns */ + WIDTHLOOP( i, width ) + { + lm_move_to( lmp, p, FALSE, TRUE ); + lm_draw_line( lmp, p2, FALSE, TRUE ); + --p.h; + --p2.h; + } + } + + { + XinRect r; + + r = lmp->rct; + r.left = lmp->rct.right - lmp->rct.left; + r.right = SHRT_MAX; + if ( lmp->no_vert_lines ) + r.left -= BORDER_WIDTH; + XinWindowPenSet( win, &hollow_cpen ); + cbrush.pattern = XinBrushSolid; + cbrush.fore_color = lmp->white_space_color; + XinWindowBrushSet( win, &cbrush ); + xi_set_clip( win, actual_rct ); + + lm_draw_rect( lmp, &r, FALSE ); + } + + /* draw border around entire list */ + lmp_rct.right = actual_r; + { + XinRect r; + XinBrush cb; + + r = lmp->rct; + if ( list_data->sb_win ) + { + xi_get_sb_rect( list_obj, &vr ); + /* add one, so that one pixel of the double border will overlap one + * pixel of the scroll bar. */ + r.right = vr.right + 1; + } + else if ( list_data->hsb_win ) + r.right = r.left + lmp->pixel_width + 2 * BORDER_WIDTH; + xi_get_hsb_rect( list_obj, &hr ); + r.bottom = hr.bottom + 1; + XinWindowBrushSet( win, &hollow_cbrush ); + XinWindowPenSet( win, &black_cpen ); + xi_set_clip( win, NULL ); + xi_draw_rect( win, &r ); + xi_inflate_rect( &r, -1 ); + xi_draw_rect( win, &r ); + + cb = white_cbrush; + cb.fore_color = lmp->white_space_color; + XinWindowBrushSet( win, &cb ); + XinWindowPenSet( win, &hollow_cpen ); + r.left += 1; + r.top = lmp->rct.bottom; + r.right -= 1; + r.bottom -= 1; + xi_draw_rect( win, &r ); + } + } + + /* RGM: Changed this rectangle to stop at the top of the horizontal scroll + * bar instead of the bottom. The bottom area is drawn just above. Was this + * rectangle supposed to draw both? If so, it is drawing over the line at the + * bottom of the list, when there are fixed columns. */ + { /* rectangle at bottom of list */ + XinRect r; + XinRect hsb_rect; + + xi_get_hsb_rect( lmp->list_obj, &hsb_rect ); + cbrush.pattern = XinBrushSolid; + cbrush.fore_color = lmp->white_space_color; + XinWindowBrushSet( win, &cbrush ); + r = lmp->mlr; + r.top = lmp->rrr_bottom + lmp->rrr_offset + lmp->mlr.top; + r.top = min( r.top, hsb_rect.top ); + r.bottom = hsb_rect.top; + r.right = lmp->rct.right; + if ( lmp->pixel_width ) + r.right = lmp->rct.left + lmp->pixel_width + 2; + xi_draw_rect( win, &r ); + } + + /* border around entire list */ + if ( !( lmp->update_rows_at_top + lmp->update_rows_at_bottom ) ) + { + XinWindowPenSet( win, &black_cpen ); + XinWindowBrushSet( win, &hollow_cbrush ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + xi_set_clip( win, NULL ); + lmp_rct = lmp->rct; + if ( lmp->pixel_width ) + lmp_rct.right = hrule_h; + WIDTHLOOP( i, BORDER_WIDTH ) + { + xi_draw_rect( win, &lmp_rct ); + xi_inflate_rect( &lmp_rct, -1 ); + } + } + +#endif +#if XIWS == XIWS_WM + xi_set_clip( win, actual_rct ); + XinWindowPenSet( win, &black_cpen ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + if ( lmp->pixel_width ) + { + XinRect r; + XinPoint p1, + p2; + + r = lmp->rct; + r.left = lmp->rct.right - lmp->rct.left + BORDER_WIDTH; + r.top += BORDER_WIDTH; + r.right = 9999; + XinWindowPenSet( win, &hollow_cpen ); + cbrush.pat = XinPatternSolid; + cbrush.color = lmp->white_space_color; + XinWindowPaintBrushSet( win, &cbrush ); + xi_set_clip( win, actual_rct ); + lm_draw_rect( lmp, &r, FALSE ); + + XinWindowPenSet( win, &black_cpen ); + p1.h = r.left; + p1.v = lmp->rct.top; + p2.h = r.left; + p2.v = r.bottom; + lm_move_to( lmp, p1, FALSE, TRUE ); + lm_draw_line( lmp, p2, FALSE, TRUE ); + + } + + { /* rectangle at bottom of list */ + XinRect r; + + cbrush.pat = XinPatternSolid; + cbrush.color = lmp->white_space_color; + XinWindowPaintBrushSet( win, &cbrush ); + XinWindowPenSet( win, &hollow_cpen ); + r = lmp->mlr; + r.left += BORDER_WIDTH; + r.top = lmp->rrr_bottom + lmp->rrr_offset + lmp->mlr.top; + r.right = lmp->rct.right; + if ( lmp->pixel_width ) + r.right = lmp->rct.left + 2 * lmp->pixel_width; + if ( r.top < r.bottom ) + xi_draw_rect( win, &r ); + } +#endif + lmp->update_rows_at_top = 0; + lmp->update_rows_at_bottom = 0; + lmp->update_cells_only = FALSE; +} + + +/*------------------------------------------------------------------------- +function: lm_size_hit_test +lm: current lm +ep: xvt event +columnp: column, to be filled in +returns: FALSE if hit test did not fall on place where column could be sized. +-------------------------------------------------------------------------*/ +static BOOLEAN +lm_size_hit_test( LM lm, XinEvent * ep, int *columnp ) +{ + int column, + temp, + col_offset; + LM_DATA *lmp = LMP( lm ); + XinPoint where; + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + where = ep->v.mouse.where; + if ( where.h < 0 ) + return FALSE; + if ( lmp->pixel_width && ( where.h > ( lmp->pixel_width + lmp->delta_x ) + + 2 * BORDER_WIDTH ) ) + return FALSE; + if ( where.v > lmp->pix_top && where.v < lmp->pix_row1_top ) + { + for ( column = 0; column < lmp->nbr_columns; column++ ) + { + LM_COLUMN_DATA *column_data; + + if ( column >= lmp->fixed_columns && column < lmp->first_vis ) + continue; + column_data = lmp->lm_column_data[column]; + temp = column_data->x_pix_pos + + col_offset + + column_data->pix_width; + if ( where.h >= temp && + where.h < temp + col_offset * 2 + RULE_WIDTH_V ) + { + *columnp = column; + return TRUE; + } + } + return FALSE; + } + return FALSE; +} + +static void +draw_cell_text( LM_DATA * lmp, LM_CELL_DATA * cell_data, LM_COLUMN_DATA * column_data, + int row, int col, int col_offset, int leading, int ascent, + int descent, XinColor fore_color, XinColor back_color, BOOLEAN set_clip ) +{ + XinRect rct; + unsigned long attrib, + cell_attrib; + char *s; + int len, + baseline, + wid; + XinWindow win = lmp->win; + + if ( lm_focus_cell_has( lmp, row, col, FALSE ) && !cell_data->button_full_cell ) + return; + + cell_attrib = cell_data->attrib & + ( XI_ATR_HCENTER | XI_ATR_RJUST ); + attrib = LM_COL_ATTR( lmp, col ) | XI_ATR_VISIBLE | + ( lmp->min_cell_height ? XI_ATR_VCENTER : 0 ); + if ( cell_attrib ) + { + attrib &= ~( XI_ATR_HCENTER | XI_ATR_RJUST ); + attrib |= cell_attrib; + } + if ( cell_data->button_full_cell ) + attrib = attrib | XI_ATR_HCENTER | XI_ATR_VCENTER; + lm_xi_text_prect_get( lmp, column_data, cell_data, row, col, col_offset, leading, + ascent, descent, &rct ); + xi_text_prect_set( cell_data->xi_text, &rct ); + if ( column_data->wrap_text ) + { + XinRect mlr = lmp->mlr; + + if ( lmp->pixel_width ) + mlr.right = mlr.left + lmp->pixel_width + BORDER_WIDTH; + xi_text_max_lines_to_draw_set( cell_data->xi_text, lmp->max_lines_in_cell ); + xi_text_draw( cell_data->xi_text, fore_color, back_color, FALSE ); + } + else + { + if ( set_clip ) + { + XinRect mlr = lmp->mlr; + XinRect cell_rct; + + if ( lmp->pixel_width ) + mlr.right = mlr.left + lmp->pixel_width + BORDER_WIDTH; + cell_rct = rct; + if ( cell_data->button_full_cell ) + { + xi_inflate_rect( &cell_rct, -2 ); + } + xi_rect_intersect( &cell_rct, &mlr, &cell_rct ); + xi_set_clip( win, &cell_rct ); + } + s = xi_get_text_string( xi_text_get( cell_data->xi_text ), LM_COL_ATTR( lmp, col ) ); + len = strlen( s ); +#if XIWS == XIWS_WM + baseline = rct.top + 8; +#else + if ( attrib & XI_ATR_VCENTER ) + baseline = rct.top + leading + ascent + + ( rct.bottom - rct.top - leading - ascent - descent ) / 2 - 1; + else + baseline = rct.top + leading + ascent; +#endif + if ( attrib & XI_ATR_RJUST ) + { + XinWindowFontMap( win, lmp->cur_font ); + wid = XinFontTextWidthGet( lmp->cur_font, s, -1 ); + xi_draw_text( win, lmp->cur_font, rct.right - wid, baseline, s, len ); + } + else + { + if ( attrib & XI_ATR_HCENTER ) + { + int x; + + wid = XinFontTextWidthGet( lmp->cur_font, s, len ); + x = ( rct.left + rct.right ) / 2 - wid / 2; + if ( x < rct.left ) + x = rct.left; + xi_draw_text( win, lmp->cur_font, x, baseline, s, len ); + } + else + xi_draw_text( win, lmp->cur_font, rct.left, baseline, s, len ); + } + } +} + +/*------------------------------------------------------------------------- +function: redraw_cell_button +lmp: current lmp +row: +col: 0 +clip_rct: clip rectangle +down: if TRUE, then button is depressed +-------------------------------------------------------------------------*/ +static void +redraw_cell_button( LM_DATA * lmp, int row, int col, XinRect * clip_rct, + BOOLEAN down, BOOLEAN clear_button ) +{ + XinRect r, + outer_rct, + col_rct, + clip_rect; + int cell_btn_icon_x, + cell_btn_icon_y; + LM_CELL_DATA *cell_data; + BOOLEAN button_on_left; + BOOLEAN button_full_cell; + int button_icon_rid; + LM_COLUMN_DATA *column_data; + XinPoint p; + XinDrawTools ct; + XinRect actual_rct; + int actual_r; + + actual_rct = lmp->rct; +#if XIWS != XIWS_WM + if ( lmp->pixel_width ) + actual_r = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH; + else + actual_r = lmp->rct.right; + actual_rct.right = actual_r - BORDER_WIDTH; +#else + if ( lmp->pixel_width ) + actual_r = lmp->rct.left + lmp->pixel_width; + else + actual_r = lmp->rct.right; + actual_rct.right = actual_r; +#endif + column_data = lmp->lm_column_data[col]; + col_rct.left = column_data->x_pix_pos; + col_rct.right = col_rct.left + column_data->pix_width + + 2 * ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + col_rct.top = clip_rct->top; + col_rct.bottom = clip_rct->bottom; + cell_data = &lmp->cell_data[row][col]; + button_on_left = cell_data->button_on_left; + button_full_cell = cell_data->button_full_cell; + button_icon_rid = cell_data->button_icon_rid; + lm_get_cell_rect( &outer_rct, ( LM ) lmp, row, col, FALSE, FALSE ); + r = outer_rct; + xi_inflate_rect( &r, 1 ); + if ( !button_full_cell ) + { + if ( button_on_left ) + { + r.right = r.left + lmp->pix_row_spacing; + p.h = r.right - 1; + } + else + { + r.left = r.right - lmp->pix_row_spacing; + p.h = r.left; + } + } + XinWindowPenSet( lmp->win, &black_cpen ); + XinWindowDrawModeSet( lmp->win, XinDrawModeCopy ); + clip_rect = col_rct; + clip_rect.left += lmp->rct.left; + clip_rect.right += lmp->rct.left; + + lm_adj_h( lmp, &clip_rect.left ); + lm_adj_h( lmp, &clip_rect.right ); + xi_rect_intersect( &clip_rect, &clip_rect, &lmp->mlr ); + xi_rect_intersect( &clip_rect, &clip_rect, &actual_rct ); + xi_set_clip( lmp->win, &clip_rect ); + if ( clear_button ) + { + if ( lmp->no_horz_lines ) + { + /* if there is a button below, then decrement r.bottom */ + int nr; + LM_CELL_DATA *row_below_cell_data; + + nr = row; + row_below_cell_data = &lmp->cell_data[nr + 1][col]; + if ( row < lmp->nbr_realized_rows - 1 && + row_below_cell_data->button && + row_below_cell_data->button_on_left == lmp->cell_data[nr][col].button_on_left && + row_below_cell_data->button_full_cell == lmp->cell_data[nr][col].button_full_cell && + ( !row_below_cell_data->button_on_focus ) ) + r.bottom--; + + XinWindowPenSet( lmp->win, &hollow_cpen ); + XinWindowBrushSet( lmp->win, &white_cbrush ); + lm_draw_rect( lmp, &r, TRUE ); + } + return; + } + if ( lmp->no_horz_lines || lmp->no_vert_lines ) + lm_draw_rect( lmp, &r, TRUE ); + else + { + p.v = r.top; + lm_move_to( lmp, p, TRUE, TRUE ); + p.v = r.bottom; + lm_draw_line( lmp, p, TRUE, TRUE ); + } + xi_inflate_rect( &r, -1 ); + lm_draw_3d_rect( lmp, &r, down, 2, TRUE ); + xi_inflate_rect( &r, -2 ); + + // Guy was here: le icone vanno centrate nel bottone + // cell_btn_icon_x = ( int ) xi_get_pref( XI_PREF_CELL_BTN_ICON_X ); + // cell_btn_icon_y = ( int ) xi_get_pref( XI_PREF_CELL_BTN_ICON_Y ); + cell_btn_icon_x = (r.right-r.left - XinMetricGet(XinMetricIconWidth))/2; + cell_btn_icon_y = (r.bottom-r.top - XinMetricGet(XinMetricIconHeight))/2; + + r.left = max( r.left, col_rct.left ); + r.right = min( r.right, col_rct.right ); + XinWindowDrawToolsGet( lmp->win, &ct ); + ct.text_fore_color = lmp->enabled_color; + ct.text_back_color = aga_get_pref( AGA_PREF_BTN_COLOR_CTRL ); + ct.opaque_text = FALSE; + if ( lmp->row_colors[row] ) + ct.text_fore_color = lmp->row_colors[row]; + if ( cell_data->color ) + ct.text_fore_color = cell_data->color; + XinWindowDrawToolsSet( lmp->win, &ct ); + if ( !button_full_cell ) + { + lm_draw_icon( lmp, r.left + cell_btn_icon_x, r.top + cell_btn_icon_y + down, + button_icon_rid ? button_icon_rid : ( int ) xi_get_pref( XI_PREF_COMBO_ICON ), + cell_data->button_bitmap, clip_rct, &r, TRUE, XI_COLOR_BLACK, + aga_get_pref( AGA_PREF_BTN_COLOR_CTRL ) ); + } + else if ( button_full_cell && ( cell_data->icon_rid || cell_data->bitmap != NULL ) ) + { + lm_draw_icon( lmp, r.left, r.top, cell_data->icon_rid, cell_data->bitmap, + clip_rct, &r, TRUE, XI_COLOR_BLACK, aga_get_pref( AGA_PREF_BTN_COLOR_CTRL ) ); + } + else + { + LM_CELL_DATA *cell_data; + int col_offset; + int leading, + ascent, + descent; + + cell_data = &lmp->cell_data[row][col]; + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + XinFontMetricsGet( lmp->cur_font, &leading, &ascent, &descent ); + draw_cell_text( lmp, cell_data, column_data, + row, col, col_offset, leading, ascent, + descent, 0L, 0L, TRUE ); + if ( lm_focus_cell_has( lmp, row, col, FALSE ) ) + { + XinRect mlr = lmp->mlr; + XinRect cell_rct, + clip_rct, + text_rct; + int baseline; + + if ( lmp->pixel_width ) + mlr.right = mlr.left + lmp->pixel_width + BORDER_WIDTH; + lm_xi_text_prect_get( lmp, column_data, cell_data, row, col, col_offset, leading, + ascent, descent, &cell_rct ); + xi_rect_intersect( &clip_rct, &mlr, &cell_rct ); + xi_set_clip( lmp->win, &clip_rct ); +#if XIWS == XIWS_WM + baseline = cell_rct.top + 8; +#else + baseline = cell_rct.top + leading + ascent + + ( cell_rct.bottom - cell_rct.top - leading - ascent - descent ) / 2 - 1; +#endif + text_rct = cell_rct; + text_rct.top = baseline - leading - ascent - 2; + text_rct.top = max( text_rct.top, ( cell_rct.top ) ); + text_rct.bottom = baseline + descent + 2; + text_rct.bottom = min( text_rct.bottom, ( cell_rct.bottom - 2 ) ); + XinWindowPenSet( lmp->win, &black_cpen ); + XinWindowDrawModeSet( lmp->win, XinDrawModeCopy ); + xi_draw_dotted_rect( lmp->win, &text_rct ); + } + } +} + +static void +draw_cell_buttons( LM_DATA * lmp, ROW_INFO * row_info, int first_row, int last_row, + BOOLEAN in_update_event ) +{ + int col, + row; + LM_COLUMN_DATA *column_data; + ROW_INFO *ri; + + NOREF( in_update_event ); + /* draw exception rectangles - draw enabled, not selected cells */ + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + XinRect mr; + BOOLEAN button; + BOOLEAN button_on_focus; + BOOLEAN button_full_cell; + LM_CELL_DATA *cell_data; + + if ( !ri->XinWindowPaintNeeds ) + continue; + mr = lmp->mlr; + if ( lmp->pixel_width ) + mr.right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH; + cell_data = &lmp->cell_data[row][col]; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + button = cell_data->button; + button_on_focus = cell_data->button_on_focus; + button_full_cell = cell_data->button_full_cell; + if ( lmp->button_on_cell_focus ) + { + if ( ( button && !button_on_focus ) || + ( button && button_full_cell ) || + ( button && button_on_focus && + lm_focus_cell_has( lmp, row, col, FALSE ) ) ) + redraw_cell_button( lmp, row, col, &mr, FALSE, FALSE ); + } + else + { + if ( ( button && !button_on_focus ) || + ( button && button_full_cell ) || + ( button && button_on_focus && + lm_row_has_focus( lmp, row, FALSE ) ) ) + redraw_cell_button( lmp, row, col, &mr, FALSE, FALSE ); + } + } + } +} + +/*------------------------------------------------------------------------- +function: lm_XinWindowPaintNeeds +lmp: current lmp +rctp: rectangle to test +adj_h: adjust h +adj_v: adjust v +returns: TRUE if rectangle needs update +-------------------------------------------------------------------------*/ +static BOOLEAN +lm_XinWindowPaintNeeds( LM_DATA * lmp, XinRect * rctp, BOOLEAN adj_h, BOOLEAN adj_v ) +{ + XinRect r; + + r = *rctp; + if ( adj_h ) + { + r.left += lmp->rct.left; + r.right += lmp->rct.left; + } + + if ( adj_v ) + { + lm_adj_v( lmp, r.top ); + lm_adj_v( lmp, r.bottom ); + } + + if ( adj_h ) + { + BOOLEAN leftb, + rightb; + + leftb = lm_adj_h( lmp, &r.left ); + rightb = lm_adj_h( lmp, &r.right ); + if ( !leftb && !rightb ) + return FALSE; + } + xi_offset_rect( &r, -lmp->list_obj->itf->v.itf->delta_x, + -lmp->list_obj->itf->v.itf->delta_y ); + return XinWindowPaintNeeds( lmp->win, &r ); +} + +/* ------------------------------------------------------------------------- */ +/* calc_col_XinWindowPaintNeeds */ +/* ------------------------------------------------------------------------- */ +static void +calc_col_XinWindowPaintNeeds( LM_DATA * lmp, int first_col, int last_col, + BOOLEAN update ) +{ + int col; + LM_COLUMN_DATA *column_data; + +#if XIWS == XIWS_WM + NOREF( update ); +#endif + + for ( col = 0; col < lmp->nbr_columns; ++col ) + lmp->lm_column_data[col]->XinWindowPaintNeeds = FALSE; + for ( col = first_col; col <= last_col; ++col ) + { + XinRect rct; + BOOLEAN rightb, + leftb; + + column_data = lmp->lm_column_data[col]; + if ( column_data->suppress_update_cells ) + continue; + rct.left = lmp->rct.left + column_data->x_pix_pos; + rct.right = rct.left + column_data->pix_width + + 2 * ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + rct.top = lmp->rct.top; + rct.bottom = lmp->rct.bottom; + column_data->column_rct = rct; +#if XIWS != XIWS_WM + leftb = lm_adj_h( lmp, &rct.left ); + rightb = lm_adj_h( lmp, &rct.right ); + column_data->prct = rct; + if ( !leftb && !rightb ) + column_data->XinWindowPaintNeeds = FALSE; + else + { + if ( update ) + { + if ( xi_XinWindowPaintNeeds( lmp->win, &column_data->prct ) ) + column_data->XinWindowPaintNeeds = TRUE; + else + column_data->XinWindowPaintNeeds = FALSE; + } + else + column_data->XinWindowPaintNeeds = TRUE; + } +#else + leftb = lm_adj_h( lmp, &rct.left ); + rightb = lm_adj_h( lmp, &rct.right ); + column_data->prct = rct; + if ( !leftb && !rightb ) + column_data->XinWindowPaintNeeds = FALSE; + else + column_data->XinWindowPaintNeeds = TRUE; +#endif + } +} + +/*********** draw row rules ***********/ +static void +draw_row_rules( LM_DATA * lmp, int first_row_to_draw, int last_row_to_draw, BOOLEAN update ) +{ + int r2, + first_row, + last_row; + int row, + actual_r, + hrule_h, + col; + XinPoint p; + XinRect r; + XinRect actual_rct = lmp->mlr; + +#if XIWS != XIWS_WM + if ( lmp->pixel_width ) + actual_r = actual_rct.left + lmp->pixel_width; + else + actual_r = lmp->rct.right; + actual_rct.right = actual_r; +#else + if ( lmp->pixel_width ) + actual_r = lmp->rct.left + lmp->pixel_width; + else + actual_r = lmp->rct.right; + actual_rct.right = actual_r; +#endif + hrule_h = actual_r; + xi_set_clip( lmp->win, &actual_rct ); + + if ( lmp->no_horz_lines ) + { + XinPen back_cpen; + + back_cpen = black_cpen; + back_cpen.fore_color = lmp->back_color; + XinWindowPenSet( lmp->win, &back_cpen ); + } + else + { +#if XIWS != XIWS_WM + XinPen back_cpen; + + back_cpen = black_cpen; + back_cpen.fore_color = lmp->rule_color; + XinWindowPenSet( lmp->win, &back_cpen ); +#else + XinWindowPenSet( lmp->win, &black_cpen ); +#endif + } + r2 = lmp->rct.right - lmp->delta_x; + r2 = min( r2, hrule_h ); + if ( r2 < hrule_h && lmp->no_vert_lines ) + r2 -= 2; + + first_row = max( 0, lmp->first_fully_vis - 1 ); + last_row = min( lmp->nbr_realized_rows, lmp->last_fully_vis + 1 ); + + if ( lmp->update_rows_at_top ) + { + XinRect row_rct; + int old_last_row = last_row; + + last_row = min( last_row, first_row + lmp->update_rows_at_top + 1 ); + lm_get_row_rect( &row_rct, ( LM ) lmp, last_row ); + row_rct.bottom = lmp->mlr.bottom - lmp->mlr.top; + if ( update && lm_XinWindowPaintNeeds( lmp, &row_rct, FALSE, TRUE ) ) + last_row = old_last_row; + } + if ( lmp->update_rows_at_bottom ) + { + XinRect row_rct; + int old_first_row = first_row; + + first_row = max( first_row, lmp->last_fully_vis - lmp->update_rows_at_bottom ); + lm_get_row_rect( &row_rct, ( LM ) lmp, first_row ); + row_rct.top = 0; + if ( update && lm_XinWindowPaintNeeds( lmp, &row_rct, FALSE, TRUE ) ) + first_row = old_first_row; + } + + if ( first_row_to_draw != -1 ) + { + first_row = max( first_row_to_draw - 1, first_row ); + last_row = min( last_row_to_draw + 1, last_row ); + } + + if ( lmp->no_horz_lines && !lmp->no_vert_lines ) + { /* Draw between the vertical lines */ + for ( col = 0; col < lmp->nbr_columns; ++col ) + if ( !lmp->lm_column_data[col]->suppress_update_cells ) + { + lm_get_rect( ( LM ) lmp, LM_COLUMN, col, &r ); + if ( lmp->pixel_width != 0 && r.left > lmp->pixel_width ) + break; + for ( row = first_row; row < last_row; row++ ) + { + p.h = r.left; + p.v = lmp->pix_offsets[row] + lmp->pix_heights[row] - 1; + lm_move_to( lmp, p, TRUE, FALSE ); + p.h = r.right; + lm_draw_line( lmp, p, TRUE, FALSE ); + } + } + } + else + { /* Draw single lines all the way across the + * list */ + r = lmp->rct; + for ( col = 0; col < lmp->nbr_columns; ++col ) + if ( !lmp->lm_column_data[col]->suppress_update_cells ) + break; + if ( col ) + r.left = lmp->lm_column_data[col]->x_pix_pos; + + for ( row = first_row; row < last_row; ++row ) + { + p.h = r.left; + p.v = lmp->pix_offsets[row] + lmp->pix_heights[row] - 1; + lm_move_to( lmp, p, TRUE, FALSE ); + p.h = r2; + lm_draw_line( lmp, p, TRUE, FALSE ); + } + } +} + +static void +draw_background_rects( LM_DATA * lmp, XinWindow win, ROW_INFO * row_info, + int first_row, int last_row ) +{ + XinColor last_brush_color; + int col, + row; + int focus_row, + focus_column; + BOOLEAN v_scrolled; + LM_COLUMN_DATA *column_data; + ROW_INFO *ri; + extern XinPen hollow_cpen; + BOOLEAN list_has_focus; + + list_has_focus = lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + + /* draw exception rectangles - draw enabled, not selected cells */ + last_brush_color = 0xFFFFFFFFL; /* this is a value that will never be + * used for an actual color, so that + * the background color will be set + * properly the first time through */ + XinWindowPenSet( win, &hollow_cpen ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + XinColor brush_color; + LM_CELL_DATA *cell_data = &lmp->cell_data[row][col]; + BOOLEAN do_draw; + + if ( !ri->XinWindowPaintNeeds ) + continue; + if ( list_has_focus && !v_scrolled && col == focus_column && row == focus_row ) + continue; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + do_draw = lm_focus_cell_has( lmp, row, col, FALSE ); + if ( ( CELL_IS_ENABLED( lmp, row, col ) ) && !( CELL_IS_SELECTED( lmp, row, col ) ) ) + do_draw = TRUE; + if ( do_draw ) + { + XinRect rct; + + brush_color = lmp->back_color; + if ( cell_data->back_color ) + brush_color = cell_data->back_color; +/* +TO OPTIMIZE BACKGROUND DRAWING, USE NEXT TWO LINES + if (brush_color == lmp->back_color) + continue; +*/ + if ( brush_color != last_brush_color ) + { + XinBrush cbrush; + + cbrush.fore_color = brush_color; + cbrush.pattern = XinBrushSolid; + XinWindowBrushSet( win, &cbrush ); + } + rct = column_data->prct; + rct.top = ri->prct.top; + rct.bottom = ri->prct.bottom; + xi_draw_rect( win, &rct ); + } + } + } + + /* draw exception rectangles - draw disabled, not selected cells */ + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + XinColor brush_color; + LM_CELL_DATA *cell_data = &lmp->cell_data[row][col]; + + if ( !ri->XinWindowPaintNeeds ) + continue; + if ( list_has_focus && !v_scrolled && col == focus_column && row == focus_row ) + continue; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + if ( !( CELL_IS_ENABLED( lmp, row, col ) ) && !( CELL_IS_SELECTED( lmp, row, col ) ) ) + { + XinRect rct; + + brush_color = lmp->disabled_back_color; +/* +TO OPTIMIZE BACKGROUND DRAWING, USE NEXT TWO LINES + if (brush_color == lmp->back_color) + continue; +*/ + if ( brush_color != last_brush_color ) + { + XinBrush cbrush; + + cbrush.fore_color = brush_color; + cbrush.pattern = XinBrushSolid; + XinWindowBrushSet( win, &cbrush ); + } + rct = column_data->prct; + rct.top = ri->prct.top; + rct.bottom = ri->prct.bottom; + xi_draw_rect( win, &rct ); + } + } + } + + /* draw exception rectangles - draw selected cells */ + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + XinColor brush_color; + LM_CELL_DATA *cell_data = &lmp->cell_data[row][col]; + + if ( !ri->XinWindowPaintNeeds ) + continue; + if ( list_has_focus && !v_scrolled && col == focus_column && row == focus_row ) + continue; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + if ( CELL_IS_SELECTED( lmp, row, col ) && !lm_focus_cell_has( lmp, row, col, FALSE ) ) + { + XinRect rct; + + if ( CELL_IS_ENABLED( lmp, row, col ) ) + { + brush_color = lmp->enabled_color; + if ( lmp->row_colors[row] ) + brush_color = lmp->row_colors[row]; + if ( cell_data->color ) + brush_color = cell_data->color; + } + else + brush_color = lmp->disabled_color; + if ( cell_data->back_color && lmp->retain_back_color_on_select ) + brush_color = cell_data->back_color; +/* +TO OPTIMIZE BACKGROUND DRAWING, USE NEXT TWO LINES + if (brush_color == lmp->back_color) + continue; +*/ + if ( brush_color != last_brush_color ) + { + XinBrush cbrush; + + cbrush.fore_color = brush_color; + cbrush.pattern = XinBrushSolid; + XinWindowBrushSet( win, &cbrush ); + } + rct = column_data->prct; + rct.top = ri->prct.top; + rct.bottom = ri->prct.bottom; + xi_draw_rect( win, &rct ); + } + } + } + +#if XIWS != XIWS_WM + /* draw 3d rectangles */ + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + XinRect rct; + LM_CELL_DATA *cell_data = &lmp->cell_data[row][col]; + + if ( !ri->XinWindowPaintNeeds ) + continue; + if ( list_has_focus && !v_scrolled && col == focus_column && row == focus_row ) + continue; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + + rct = column_data->prct; + rct.top = ri->prct.top; + rct.bottom = ri->prct.bottom; + if ( column_data->column_well || column_data->column_platform ) + { + const XinColor color_light = aga_get_pref(AGA_PREF_BTN_COLOR_LIGHT); + const XinColor color_ctrl = aga_get_pref(AGA_PREF_BTN_COLOR_CTRL); + const XinColor color_dark = aga_get_pref(AGA_PREF_BTN_COLOR_DARK); + + if ( xi_get_pref( XI_PREF_3D_LOOK ) ) + xi_draw_shaded_rect( win, &rct, ( BOOLEAN ) ( CELL_IS_SELECTED( lmp, row, col ) ? !column_data->column_well : + column_data->column_well ), 2, color_light, color_ctrl, color_dark ); + else + xi_draw_3d_rect( win, &rct, ( BOOLEAN ) ( CELL_IS_SELECTED( lmp, row, col ) ? !column_data->column_well : + column_data->column_well ), 2, color_light, color_ctrl, color_dark ); + } + } + } +#else + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + XinColor brush_color; + LM_CELL_DATA *cell_data = &lmp->cell_data[row][col]; + BOOLEAN do_draw; + + if ( !ri->XinWindowPaintNeeds ) + continue; + if ( list_has_focus && !v_scrolled && col == focus_column && row == focus_row ) + continue; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + do_draw = lm_focus_cell_has( lmp, row, col, FALSE ); + if ( ( CELL_IS_ENABLED( lmp, row, col ) ) && !( CELL_IS_SELECTED( lmp, row, col ) ) ) + do_draw = TRUE; + if ( do_draw ) + { + if ( column_data->column_well || column_data->column_platform ) + { + XinRect rct; + + brush_color = lmp->back_color; + if ( cell_data->back_color ) + brush_color = cell_data->back_color; + if ( brush_color != last_brush_color ) + { + XinBrush cbrush; + + cbrush.color = brush_color; + cbrush.pat = XinPatternSolid; + XinWindowPaintBrushSet( win, &cbrush ); + } + rct = column_data->prct; + rct.top = ri->prct.top; + rct.bottom = ri->prct.bottom; + xi_draw_rect( win, &rct ); + } + } + } + } +#endif + if ( list_has_focus && !v_scrolled && focus_row >= first_row && focus_row <= last_row ) + { + XinColor brush_color; + LM_CELL_DATA *cell_data = &lmp->cell_data[focus_row][focus_column]; + XinBrush cbrush; + XinRect rct, + row_rect; + + column_data = lmp->lm_column_data[focus_column]; + if ( column_data->XinWindowPaintNeeds ) + { + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, focus_row, focus_column, FALSE ); + brush_color = lmp->active_back_color; // Big brained XI put here lmp->back_color! + if ( cell_data->back_color ) + brush_color = cell_data->back_color; + + cbrush.fore_color = brush_color; + cbrush.pattern = XinBrushSolid; + XinWindowBrushSet( win, &cbrush ); + rct = column_data->prct; + lm_get_row_rect( &row_rect, ( LM ) lmp, focus_row ); +#if XIWS != XIWS_WM + row_rect.bottom--; + if ( row_rect.bottom < row_rect.top ) + row_rect.bottom = row_rect.top; +#endif + lm_adj_v( lmp, row_rect.top ); + lm_adj_v( lmp, row_rect.bottom ); + rct.top = row_rect.top; + rct.bottom = row_rect.bottom; +#if XIWS == XIWS_MAC || XIWS == XIWS_XM || XIWS == XIWS_WXGTK + if ( cell_data->xi_text ) + xi_text_rect_get_adjusted( cell_data->xi_text, &rct ); +#endif + xi_draw_rect( win, &rct ); + } + } +} + +static void +draw_cell_icons( LM_DATA * lmp, XinWindow win, ROW_INFO * row_info, + int first_row, int last_row ) +{ + int col, + row; + LM_COLUMN_DATA *column_data; + ROW_INFO *ri; + XinDrawTools ct; + XinColor last_fore_color, + last_back_color; + + XinWindowDrawToolsGet( win, &ct ); + ct.text_fore_color = lmp->enabled_color; + ct.text_back_color = lmp->back_color; + ct.opaque_text = TRUE; + XinWindowDrawToolsSet( win, &ct ); + last_back_color = 0L; + last_fore_color = 0L; + /* draw cell icons */ + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + XinRect rct; + LM_CELL_DATA *cell_data = &lmp->cell_data[row][col]; + XinColor fore_color, + back_color; + + if ( !ri->XinWindowPaintNeeds ) + continue; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + rct = column_data->prct; + rct.top = ri->rct.top; + rct.bottom = ri->rct.bottom; + lm_adj_v( lmp, rct.top ); + lm_adj_v( lmp, rct.bottom ); + { + XinRect mlr = lmp->mlr; + + if ( lmp->pixel_width ) + mlr.right = mlr.left + lmp->pixel_width + BORDER_WIDTH; + xi_rect_intersect( &mlr, &mlr, &rct ); + xi_set_clip( win, &mlr ); + } + fore_color = ct.text_fore_color; + back_color = ct.text_back_color; + if ( lmp->row_colors[row] ) + fore_color = lmp->row_colors[row]; + if ( cell_data->color ) + fore_color = cell_data->color; + if ( cell_data->back_color ) + { + back_color = cell_data->back_color; + } + if ( cell_data->bitmap != NULL && !cell_data->button_full_cell ) + { + if ( lmp->no_horz_lines ) + rct.bottom++; + if ( lmp->no_vert_lines ) + rct.right++; + xi_bitmap_draw( cell_data->bitmap, win, &rct, &rct, FALSE ); + continue; + } + if ( !cell_data->icon_rid ) + continue; + if ( cell_data->button_full_cell ) + continue; + if ( fore_color != last_fore_color || back_color != last_back_color ) + xi_draw_icon( win, rct.left, rct.top, cell_data->icon_rid, fore_color, back_color ); + else + xi_draw_icon( win, rct.left, rct.top, cell_data->icon_rid, 0L, 0L ); + } + } +} + +static void +get_cell_color( LM_DATA * lmp, LM_CELL_DATA * cell_data, LM_COLUMN_DATA * column_data, + int row, int col, XinColor * color, XinColor * back_color ) +{ + BOOLEAN list_enabled, + col_enabled, + enabled; + XinColor temp_color; + + list_enabled = ( lmp->attrib & XI_ATR_ENABLED ) != 0; + col_enabled = ( lmp->lm_column_data[col]->attrib & XI_ATR_ENABLED ) != 0; + enabled = list_enabled && col_enabled; + if ( CELL_IS_SELECTED( lmp, row, col ) ) + { + XinColor enabled_back_color, + enabled_color; + XinColor disabled_back_color, + disabled_color; + + /* determine enabled_back_color */ + enabled_back_color = lmp->back_color; + if ( cell_data->back_color ) + enabled_back_color = cell_data->back_color; + + /* determine enabled_color */ + enabled_color = lmp->enabled_color; + temp_color = lmp->row_colors[row]; + if ( temp_color ) + enabled_color = temp_color; + if ( cell_data->color ) + enabled_color = cell_data->color; + + /* determine disabled colors */ + disabled_back_color = lmp->disabled_back_color; + disabled_color = lmp->disabled_color; + + if ( enabled ) + { + if ( lmp->retain_back_color_on_select && cell_data->back_color ) + { + *color = enabled_color; + *back_color = enabled_back_color; + } + else + { + *color = enabled_back_color; + *back_color = enabled_color; + } + } + else + { + *color = disabled_back_color; + *back_color = disabled_color; + } + + if ( column_data->column_well || column_data->column_platform ) + *color = lmp->enabled_color; + } + else + { + if ( enabled ) + { + *color = lmp->enabled_color; + temp_color = lmp->row_colors[row]; + if ( temp_color ) + *color = temp_color; + if ( cell_data->color ) + *color = cell_data->color; + *back_color = lmp->back_color; + if ( cell_data->back_color ) + *back_color = cell_data->back_color; + } + else + { + *color = lmp->disabled_color; + *back_color = lmp->disabled_back_color; + } + } + if ( column_data->wrap_text && !cell_data->back_color + && ( column_data->column_platform || column_data->column_well ) ) + *back_color = xi_get_pref( XI_PREF_COLOR_CTRL ); + else if ( *color == XI_COLOR_BLACK ) + *color = 0L; +} + +static void +draw_all_cell_text( LM_DATA * lmp, XinWindow win, ROW_INFO * row_info, + int col_offset, int first_row, int last_row, XinRect * list_rect, + BOOLEAN in_update_event ) +{ + XinDrawTools ctools; + int row, + col; + ROW_INFO *ri; + LM_COLUMN_DATA *column_data; + int leading, + ascent, + descent; + BOOLEAN have_last_font; + BOOLEAN have_set_height = FALSE; + XinFont *last_font; + + ctools = lm_normal_ctools; + + /* the following two lines must come before the XinWindowFontSet, because in + * R3, setting the draw ctools also sets the font. */ + ctools.text_fore_color = XI_COLOR_BLACK; +#if XIWS == XIWS_WM + ctools.BackColor = lmp->back_color; +#endif + XinWindowDrawToolsSet( win, &ctools ); + + lmp->cur_font = lmp->font; + XinFontMetricsGet( lmp->cur_font, &leading, &ascent, &descent ); + +/* +draw: +font: default +wrapped: no +color: black + +one of the slowest operations is setting colors, therefore we only draw text +of the most common color. after this loop, we draw text of other colors. +because this loop draws most of the cells, don't set any colors within +this loop. + +color is set to black just above. +*/ + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + int col_offset; + XinRect clip_rect, + rect; + + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + + if ( column_data->wrap_text ) + continue; + rect = column_data->prct; + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + rect.left += col_offset; + rect.right -= col_offset; + if ( !xi_rect_intersect( &clip_rect, &rect, list_rect ) ) + continue; + xi_set_clip( win, &clip_rect ); + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + LM_CELL_DATA *cell_data; + XinColor color, + back_color; + + if ( !ri->XinWindowPaintNeeds ) + continue; + cell_data = &lmp->cell_data[row][col]; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + if ( cell_data->font ) + continue; + if ( cell_data->icon_rid || cell_data->bitmap != NULL ) + continue; + if ( cell_data->button_full_cell ) + continue; + if ( lmp->set_heights[row] ) + { + have_set_height = TRUE; + continue; + } + get_cell_color( lmp, cell_data, column_data, row, col, &color, &back_color ); + if ( color ) + continue; + draw_cell_text( lmp, cell_data, column_data, + row, col, col_offset, leading, ascent, + descent, color, back_color, FALSE ); + } + } + +/* +draw: +font: default +wrapped: no +color: not black +*/ + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + XinRect clip_rect; + + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + if ( column_data->wrap_text ) + continue; + if ( !xi_rect_intersect( &clip_rect, &column_data->prct, list_rect ) ) + continue; + xi_set_clip( win, &clip_rect ); + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + LM_CELL_DATA *cell_data; + XinColor color, + back_color; + + if ( !ri->XinWindowPaintNeeds ) + continue; + cell_data = &lmp->cell_data[row][col]; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + if ( cell_data->font ) + continue; + if ( cell_data->icon_rid || cell_data->bitmap != NULL ) + continue; + if ( cell_data->button_full_cell ) + continue; + if ( lmp->set_heights[row] ) + { + have_set_height = TRUE; + continue; + } + get_cell_color( lmp, cell_data, column_data, row, col, &color, &back_color ); + if ( !color ) + continue; + XinWindowColorTextForeSet( win, color ); +#if XIWS == XIWS_WM + XinWindowColorTextBackSet( win, lmp->enabled_color ); +#endif + draw_cell_text( lmp, cell_data, column_data, row, col, col_offset, + leading, ascent, descent, color, back_color, FALSE ); + } + } + + +/* +draw: +font: default +wrapped: yes +color: black + +this needs to be a separate loop from above, because this loop sets the +clipping region for each cell, and the above loop sets the clipping region +for each column. +*/ + XinWindowColorTextForeSet( win, XI_COLOR_BLACK ); + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + if ( !column_data->wrap_text && !have_set_height ) + continue; + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + LM_CELL_DATA *cell_data; + XinColor color, + back_color; + + if ( !ri->XinWindowPaintNeeds ) + continue; + if ( lmp->row_colors[row] ) + continue; + cell_data = &lmp->cell_data[row][col]; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + if ( cell_data->font ) + continue; + if ( cell_data->icon_rid || cell_data->bitmap != NULL ) + continue; + if ( cell_data->button_full_cell ) + continue; + if ( !column_data->wrap_text && !lmp->set_heights[row] ) + continue; + get_cell_color( lmp, cell_data, column_data, row, col, &color, &back_color ); + if ( color ) + continue; + draw_cell_text( lmp, cell_data, column_data, + row, col, col_offset, leading, ascent, + descent, color, back_color, TRUE ); + } + } + +/* +draw: +font: default +wrapped: yes +color: not black + +this needs to be a separate loop from above, because this loop sets the +colors for each cell, and the above loop only draws black. +*/ + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + if ( !column_data->wrap_text && !have_set_height ) + continue; + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + LM_CELL_DATA *cell_data; + XinColor color, + back_color; + + if ( !ri->XinWindowPaintNeeds ) + continue; + cell_data = &lmp->cell_data[row][col]; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + if ( cell_data->font ) + continue; + if ( cell_data->icon_rid || cell_data->bitmap != NULL ) + continue; + if ( cell_data->button_full_cell ) + continue; + if ( !column_data->wrap_text && !lmp->set_heights[row] ) + continue; + get_cell_color( lmp, cell_data, column_data, row, col, &color, &back_color ); + if ( !color ) + continue; + XinWindowColorTextForeSet( win, color ); + draw_cell_text( lmp, cell_data, column_data, + row, col, col_offset, leading, ascent, + descent, color, back_color, TRUE ); + } + } + +/* +draw: +font: not default +wrapped: either yes or no +color: any + +draw all of the rest of the text +*/ + have_last_font = FALSE; + last_font = NULL; + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + LM_CELL_DATA *cell_data; + XinColor color, + back_color; + BOOLEAN need_to_set; + + if ( !ri->XinWindowPaintNeeds ) + continue; + cell_data = &lmp->cell_data[row][col]; + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + if ( !cell_data->font ) + continue; + if ( cell_data->icon_rid || cell_data->bitmap != NULL ) + continue; + if ( cell_data->button_full_cell ) + continue; + need_to_set = FALSE; + if ( !have_last_font ) + need_to_set = TRUE; + if ( have_last_font && !font_compare( last_font, cell_data->font ) ) + need_to_set = TRUE; + if ( need_to_set ) + { + int char_width; + + lmp->cur_font = cell_data->font; + xi_get_font_metrics_font( cell_data->font, &leading, &ascent, + &descent, &char_width ); + last_font = cell_data->font; + have_last_font = TRUE; + } + get_cell_color( lmp, cell_data, column_data, row, col, &color, &back_color ); + XinWindowColorTextForeSet( win, color ); + + draw_cell_text( lmp, cell_data, column_data, + row, col, col_offset, leading, ascent, + descent, color, back_color, TRUE ); + } + } + + if ( lm_focus_list_has( lmp ) ) + { + int focus_row, + focus_column; + BOOLEAN v_scrolled; + + if ( lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ) ) + if ( lm_focus_cell_has( lmp, focus_row, focus_column, v_scrolled ) ) + set_focus_cell_rct( lmp, focus_row, focus_column, in_update_event ); + } +} + +#if XIWS != XIWS_WM +static void +draw_row_focus_border( LM_DATA * lmp, ROW_INFO * row_info, int first_row, int last_row ) +{ + int col, + row; + LM_COLUMN_DATA *column_data; + ROW_INFO *ri; + XinPen color_cpen; + XinPen rule_cpen; + BOOLEAN last_was_rule = TRUE; + XinRect mr; + + if ( !lmp->row_focus_border ) + return; + color_cpen.width = 1; + color_cpen.fore_color = lmp->row_focus_border_color; + color_cpen.pattern = XinPenSolid; + if ( lmp->no_horz_lines ) + { + rule_cpen = black_cpen; + rule_cpen.fore_color = lmp->back_color; + } + else + { + rule_cpen.width = 1; + rule_cpen.fore_color = lmp->rule_color; + rule_cpen.pattern = XinPenSolid; + } + XinWindowPenSet( lmp->win, &rule_cpen ); + { + mr = lmp->mlr; + if ( lmp->pixel_width ) + mr.right = mr.left + lmp->pixel_width + BORDER_WIDTH; + xi_set_clip( lmp->win, &mr ); + } + for ( row = first_row, ri = &row_info[first_row]; row <= last_row; ++row, ++ri ) + { + XinRect rct; + XinPoint p; + XinWindow win = lmp->win; + BOOLEAN row_has_focus = lm_row_has_focus( lmp, row, FALSE ); + + if ( !ri->XinWindowPaintNeeds ) + continue; + if ( row_has_focus ) + { + if ( last_was_rule ) + { + XinWindowPenSet( lmp->win, &color_cpen ); + last_was_rule = FALSE; + } + } + else + { + if ( !last_was_rule ) + { + XinWindowPenSet( lmp->win, &rule_cpen ); + last_was_rule = TRUE; + } + } + for ( col = 0; col < lmp->nbr_columns; ++col ) + { + column_data = lmp->lm_column_data[col]; + if ( !column_data->XinWindowPaintNeeds ) + continue; + rct = column_data->prct; + rct.top = ri->prct.top; + rct.bottom = ri->prct.bottom; + + /* draw top line */ + p.h = rct.left; + p.v = rct.top - 1; + xi_move_to( win, p ); + p.h = rct.right; + xi_draw_line( win, p ); + + if ( row_has_focus ) + { + /* draw next line down */ + p.v++; + p.h = rct.left; + xi_move_to( win, p ); + p.h = rct.right; + xi_draw_line( win, p ); + } + + /* draw bottom line */ + p.h = rct.left; + p.v = rct.bottom; + xi_move_to( win, p ); + p.h = rct.right; + xi_draw_line( win, p ); + + if ( row_has_focus ) + { + /* draw line above bottom line */ + p.v--; + p.h = rct.left; + xi_move_to( win, p ); + p.h = rct.right; + xi_draw_line( win, p ); + } + } + } +} + +#endif + + +/* ------------------------------------------------------------------------- */ +/* draw_cell_focus_border */ +/* ------------------------------------------------------------------------- */ +static void +draw_cell_focus_border( LM_DATA * lmp ) +{ + XinColor border_color; + XinRect rct, + row_rect; + XinDrawTools dt; + int focus_row, + focus_column; + BOOLEAN v_scrolled; + LM_COLUMN_DATA *column_data; + + if ( !lm_focus_list_has( lmp ) ) + return; + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + if (v_scrolled) + return; + column_data = lmp->lm_column_data[focus_column]; + if ( !( column_data->attrib & XI_ATR_FOCUSBORDER ) ) + return; + rct = column_data->prct; + lm_get_row_rect( &row_rect, ( LM ) lmp, focus_row ); +#if XIWS != XIWS_WM + row_rect.bottom--; + if ( row_rect.bottom < row_rect.top ) + row_rect.bottom = row_rect.top; +#endif + lm_adj_v( lmp, row_rect.top ); + lm_adj_v( lmp, row_rect.bottom ); + rct.top = row_rect.top; + rct.bottom = row_rect.bottom; + border_color = lmp->enabled_color; + + XinWindowDrawToolsNormalGet( &dt ); + dt.pen.fore_color = border_color; + dt.pen.width = 1; + dt.pen.pattern = XinPenSolid; + dt.brush.pattern = XinBrushHollow; + dt.brush.fore_color = XI_COLOR_WHITE; + dt.draw_mode = XinDrawModeCopy; + XinWindowDrawToolsSet( lmp->win, &dt ); + xi_draw_rect( lmp->win, &rct ); +} + +/* ------------------------------------------------------------------------- */ +/* draw_cell_block */ +/* ------------------------------------------------------------------------- */ +static void +draw_cell_block( LM_DATA * lmp, int first_row, int last_row, + ROW_INFO * row_info, BOOLEAN in_update_event ) +{ + XinWindow win = lmp->win; + XinRect actual_rct = lmp->mlr; + int actual_r; + int col_offset; + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + +#if XIWS != XIWS_WM + if ( lmp->pixel_width ) + actual_r = lmp->mlr.left + lmp->pixel_width; + else + actual_r = lmp->mlr.right; + actual_rct.right = actual_r; +#else + if ( lmp->pixel_width ) + actual_r = lmp->mlr.left + lmp->pixel_width; + else + actual_r = lmp->mlr.right; + actual_rct.right = actual_r; +#endif + + xi_set_clip( win, &actual_rct ); + + /* draw backgrounds of cells */ + draw_background_rects( lmp, win, row_info, first_row, last_row ); + + /* draw all of the text in the cells */ + draw_all_cell_text( lmp, win, row_info, col_offset, first_row, last_row, + &actual_rct, in_update_event ); + + /* draw cell buttons */ + draw_cell_buttons( lmp, row_info, first_row, last_row, in_update_event ); + +#if XIWS != XIWS_WM + draw_row_rules( lmp, first_row, last_row, FALSE ); +#endif + + draw_cell_icons( lmp, win, row_info, first_row, last_row ); + +#if XIWS != XIWS_WM + draw_row_focus_border( lmp, row_info, first_row, last_row ); +#endif + draw_cell_focus_border( lmp ); +} + +/* ------------------------------------------------------------------------- */ +/* draw_cell_range */ +/* ------------------------------------------------------------------------- */ +void +draw_cell_range( LM_DATA * lmp, int first_row, int last_row, + int first_col, int last_col, + BOOLEAN in_event_update ) +{ + int row, + col; + ROW_INFO *row_info; + ROW_INFO *row_ptr; + + if ( lmp->list_obj->nbr_children <= 0 ) + return; + if ( xi_get_attrib( lmp->list_obj ) & XI_ATR_VISIBLE ) + { + row_info = ( ROW_INFO * ) XinMemoryAlloc( sizeof( ROW_INFO ) * ( last_row + 1 ) ); + for ( row = first_row, row_ptr = row_info + first_row; row <= last_row; + ++row, ++row_ptr ) + { + lm_get_row_rect( &row_ptr->rct, ( LM ) lmp, row ); + /* don't need to test for the rule, it is drawn elsewhere */ +#if XIWS != XIWS_WM + row_ptr->rct.bottom--; + if ( row_ptr->rct.bottom < row_ptr->rct.top ) + row_ptr->rct.bottom = row_ptr->rct.top; +#endif + row_ptr->prct = row_ptr->rct; + lm_adj_v( lmp, row_ptr->prct.top ); + lm_adj_v( lmp, row_ptr->prct.bottom ); + if ( in_event_update ) + { + if ( lm_XinWindowPaintNeeds( lmp, &row_ptr->rct, FALSE, TRUE ) ) + row_ptr->XinWindowPaintNeeds = TRUE; + else + row_ptr->XinWindowPaintNeeds = FALSE; + } + else + row_ptr->XinWindowPaintNeeds = TRUE; + } + + /* force cell requests for visible cells - makes it draw nicer */ + /* This used to be for columns with suppress_update_cells, but now applies to all */ + /* Used to have the following line as a condition for the "for" loop: */ + /* if ( lmp->lm_column_data[col]->suppress_update_cells ) */ + for ( row = first_row; row <= last_row; ++row ) + { + for ( col = first_col; col <= last_col; ++col ) + { + LM_CELL_DATA *cell_data; + + cell_data = &( lmp->cell_data[row][col] ); + if ( !cell_data->valid_data ) + do_lm_cb_text( lmp, row, col, FALSE ); + } + } + + /* determine which columns need to be updated */ + calc_col_XinWindowPaintNeeds( lmp, first_col, last_col, in_event_update ); + + /* at this point, we should never need to call lm_XinWindowPaintNeeds again + * in this function or any called functions. */ + draw_cell_block( lmp, first_row, last_row, row_info, in_event_update ); + XinMemoryFree( ( char * ) row_info ); + } +} + +/*------------------------------------------------------------------------- +function: lm_cell_btn_event +lmp: current lmp +ep: xvt event +oevp: xvt event, without virtual coordinate conversion +-------------------------------------------------------------------------*/ +static void +lm_cell_btn_event( LM_DATA * lmp, XinEvent * ep, XinEvent * oevp ) +{ + XinRect mr; + int hit_test_value, + row, + col; + + mr = lmp->mlr; + if ( lmp->pixel_width ) + mr.right = lmp->rct.left + lmp->pixel_width + BORDER_WIDTH; + + hit_test_value = lm_hit_test( ( LM ) lmp, ep, oevp, &row, &col, NULL, NULL, NULL ); + + switch ( ep->type ) + { + case XinEventMouseDown: + case XinEventMouseDouble: + lmp->down_in_btn = TRUE; + lmp->btn_down = TRUE; + lmp->btn_down_row = row; + lmp->btn_down_col = col; + XinWindowMouseTrap( lmp->win, TRUE ); + xi_set_trap_obj( lmp->list_obj ); + redraw_cell_button( lmp, row, col, &mr, lmp->btn_down, FALSE ); + break; + case XinEventMouseMove: + { + BOOLEAN last = lmp->btn_down; + + if ( hit_test_value != 5 || row != lmp->btn_down_row || col != lmp->btn_down_col ) + lmp->btn_down = FALSE; + else + lmp->btn_down = TRUE; + if ( last != lmp->btn_down ) + { + redraw_cell_button( lmp, lmp->btn_down_row, lmp->btn_down_col, &mr, + lmp->btn_down, FALSE ); + last = lmp->btn_down; + } + break; + } + case XinEventMouseUp: + { + BOOLEAN clear_button; + + { + int focus_row, + focus_col; + BOOLEAN is_vert_scrolled; + + lm_focus_cell_get( lmp, &focus_row, &focus_col, &is_vert_scrolled ); + clear_button = ( lmp->btn_down_row != focus_row ); + } + if ( lmp->btn_down && !clear_button ) + redraw_cell_button( lmp, lmp->btn_down_row, lmp->btn_down_col, &mr, + FALSE, FALSE ); + lmp->btn_down = FALSE; + lmp->down_in_btn = FALSE; + if ( hit_test_value == 5 && row == lmp->btn_down_row && col == lmp->btn_down_col ) + do_lm_cb( ( LM ) lmp, LM_CB_CELL_BTN, row, col, ep, NULL, 0 ); + else if ( clear_button ) + redraw_cell( ( LM ) lmp, lmp->btn_down_row, lmp->btn_down_col, FALSE ); + break; + } + default: + break; + } +} + +/*------------------------------------------------------------------------- +function: get_select_column +-------------------------------------------------------------------------*/ +static int +get_select_column( LM_DATA * lmp ) +{ + int col; + + for ( col = 0; col < lmp->nbr_columns; col++ ) + if ( LM_COL_ATTR( ( LM ) lmp, col ) & XI_ATR_SELECTABLE ) + return col; + return 0; +} + +/*------------------------------------------------------------------------- +function: find_selection +-------------------------------------------------------------------------*/ +static int +find_selection( LM_DATA * lmp ) +{ + int row_num; + + for ( row_num = 0; row_num < lmp->nbr_realized_rows; row_num++ ) + if ( lm_get_attrib( ( LM ) lmp, LM_ROW, row_num, 0, FALSE ) + & LM_ROW_ATR_SELECTED ) + return row_num; + return -1; +} + +/*------------------------------------------------------------------------- +function: lm_set_attrib +lm: current lm +lm_part: must be LM_LIST, LM_COLUMN, LM_ROW, or LM_CELL +idx: if LM_LIST, not used + if LM_COLUMN, column number + if LM_ROW, row number + if LM_CELL, row number +idx2: if LM_LIST, not used + if LM_COLUMN, not used + if LM_ROW, not used + if LM_CELL, column number +attrib: attribute to set +half_baked: if set, don't redraw +-------------------------------------------------------------------------*/ +void +lm_set_attrib( LM lm, LM_PART lm_part, int idx, int idx2, + BOOLEAN v_scrolled, unsigned long attrib, int half_baked ) +{ + unsigned long do_redraw; + LM_DATA *lmp = LMP( lm ); + int focus_row, + focus_column; + + switch ( lm_part ) + { + case LM_LIST: + { + XinRect r; + + lmp->attrib = attrib; + xi_get_rect( lmp->list_obj, &r ); + r.right += 10; + r.bottom += 4; + xi_invalidate_rect( lmp->win, &r ); + break; + } + case LM_COLUMN: + { + LM_COLUMN_DATA *column_data; + XinRect rct; + + column_data = lmp->lm_column_data[idx]; + do_redraw = ( ( column_data->attrib ^ attrib ) & LM_REDRAW_COL_ATR ); + if ( ( column_data->attrib ^ attrib ) + & ( LM_COL_ATR_PASSWORD | LM_COL_ATR_READONLY ) ) + { + int row; + + for ( row = 0; row < lmp->nbr_realized_rows; row++ ) + { + LM_CELL_DATA *cell_data = &lmp->cell_data[row][idx]; + + if ( cell_data->xi_text ) + { + xi_text_password_set( cell_data->xi_text, + ( attrib & LM_COL_ATR_PASSWORD ) != 0 ); + xi_text_read_only_set( cell_data->xi_text, + ( attrib & LM_COL_ATR_READONLY ) != 0 ); + } + } + } + column_data->attrib = attrib; + if ( do_redraw ) + { + BOOLEAN is_vert_scrolled; + + lm_get_rect( lm, LM_COLUMN, idx, &rct ); + xi_invalidate_rect( lmp->win, &rct ); + if ( lm_focus_cell_get( lmp, &focus_row, &focus_column, &is_vert_scrolled ) ) + if ( ( !is_vert_scrolled ) && ( focus_column == idx ) && lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE ) + set_focus_cell_rct( lmp, focus_row, focus_column, FALSE ); + } + break; + } + case LM_ROW: + { + unsigned long old_attrib; + + do_redraw = ( ( lmp->row_attribs[idx] ^ attrib ) & LM_REDRAW_ROW_ATR ); + old_attrib = lmp->row_attribs[idx]; + if ( lmp->single_select && ( attrib & XI_ATR_SELECTED ) ) + { + int old_row; + + old_row = find_selection( lmp ); + if ( old_row != -1 && old_row != idx ) + lm_set_attrib( lm, LM_ROW, old_row, 0, FALSE, + lmp->row_attribs[old_row] & ~XI_ATR_SELECTED, + half_baked ); + } + lmp->row_attribs[idx] = attrib; + if ( !half_baked && do_redraw ) + { + if ( ( old_attrib & XI_ATR_SELECTED ) != ( attrib & XI_ATR_SELECTED ) ) + { + BOOLEAN is_vert_scrolled; + + lm_redraw_row( lmp, idx, FALSE ); + if ( lm_focus_cell_get( lmp, &focus_row, &focus_column, &is_vert_scrolled ) ) + if ( ( !is_vert_scrolled ) && ( focus_row == idx ) && lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + set_focus_cell_rct( lmp, focus_row, focus_column, FALSE ); + } + else + { + XinRect r; + + lm_get_row_rect( &r, lm, idx ); + xi_set_clip( lmp->win, NULL ); + lm_invalidate_rect( lmp, &r, FALSE ); + } + } + break; + } + case LM_CELL: + { + unsigned long old_attrib; + LM_CELL_DATA *cell_data; + + cell_data = &lmp->cell_data[idx][idx2]; + if ( !cell_data->valid_data ) + return; + if ( v_scrolled ) + { + /* TODO this could be called with a v_scrolled cell when the focus is + * not really there. unlikely, but could happen. */ + lm_focus_cell_attrib_set( lmp, attrib ); + } + else + { + old_attrib = lmp->cell_data[idx][idx2].attrib; + do_redraw = ( ( old_attrib ^ attrib ) & LM_REDRAW_CELL_ATR ); + cell_data->attrib = attrib; + if ( !half_baked && do_redraw ) + { + BOOLEAN is_vert_scrolled; + + redraw_cell( lm, idx, idx2, FALSE ); + if ( lm_focus_cell_get( lmp, &focus_row, &focus_column, &is_vert_scrolled ) ) + if ( ( !is_vert_scrolled ) && ( focus_row == idx ) && ( focus_column == idx2 ) + && lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE ) + set_focus_cell_rct( lmp, focus_row, focus_column, FALSE ); + } + } + } + } +} + +/*------------------------------------------------------------------------- +function: select_row +-------------------------------------------------------------------------*/ +static void +select_row( LM lm, int row, int column, BOOLEAN dbl_click ) +{ + unsigned long attrib; + LM_CB_DATA lm_cb_data; + XI_OBJ *old_itf; + int old_row; + LM_DATA *lmp = LMP( lm ); + + old_row = find_selection( lmp ); + if ( old_row != row && old_row != -1 ) + { + attrib = lm_get_attrib( lm, LM_ROW, old_row, 0, FALSE ); + attrib &= ~LM_ROW_ATR_SELECTED; + lm_set_attrib( lm, LM_ROW, old_row, 0, FALSE, attrib, FALSE ); + } + attrib = lm_get_attrib( lm, LM_ROW, row, 0, FALSE ); + attrib |= LM_ROW_ATR_SELECTED; + lm_cb_data.lm = lm; + lm_cb_data.cb_type = LM_CB_SELECT; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) row; + if ( column == -1 ) + column = ( unsigned char ) get_select_column( lmp ); + lm_cb_data.column = column; + lm_cb_data.v.select.selected = TRUE; + lm_cb_data.v.select.dbl_click = dbl_click; + lm_cb_data.v.select.shift = FALSE; + lm_cb_data.v.select.control = FALSE; + old_itf = lmp->itf_obj; + ( *lmp->lm_cb ) ( &lm_cb_data ); + if ( xi_is_itf( old_itf ) ) + if ( !lm_cb_data.v.select.refused && old_row != row ) + lm_set_attrib( lm, LM_ROW, row, 0, FALSE, attrib, FALSE ); +} + +/*------------------------------------------------------------------------- +function: send_select_event +-------------------------------------------------------------------------*/ +static void +send_select_event( LM lm, int row, int column, XinEvent * ep, unsigned long attrib ) +{ + LM_CB_DATA lm_cb_data; + XI_OBJ *old_itf; + LM_DATA *lmp = LMP( lm ); + + if ( ep->type == XinEventMouseDouble ) + attrib |= LM_ROW_ATR_SELECTED; + else + { + if ( attrib & LM_ROW_ATR_SELECTED ) + attrib &= ~LM_ROW_ATR_SELECTED; + else + attrib |= LM_ROW_ATR_SELECTED; + } + lm_cb_data.lm = lm; + lm_cb_data.cb_type = LM_CB_SELECT; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) row; + lm_cb_data.column = ( unsigned char ) column; + lm_cb_data.v.select.selected = ( ( attrib & LM_ROW_ATR_SELECTED ) != 0 ); + lm_cb_data.v.select.dbl_click = ( ep->type == XinEventMouseDouble ); + lm_cb_data.v.select.shift = ep->v.mouse.shift; + lm_cb_data.v.select.control = ep->v.mouse.control; + old_itf = lmp->itf_obj; + ( *lmp->lm_cb ) ( &lm_cb_data ); + if ( xi_is_itf( old_itf ) ) + if ( !lm_cb_data.v.select.refused ) + lm_set_attrib( lm, LM_ROW, row, 0, FALSE, attrib, FALSE ); +} + +/*********** draw border around entire list ***********/ +static void +draw_list_rect( LM_DATA * lmp, XinRect * vr, XinRect * hr ) +{ + XinRect r; + XI_OBJ *list_obj = lmp->list_obj; + XI_LIST_DATA *list_data = list_obj->v.list; + + r = lmp->rct; + if ( list_data->sb_win ) + r.right = vr->right; + else + r.right += BORDER_WIDTH; + if ( list_data->hsb_win ) + r.bottom = hr->bottom; + xi_draw_rect( lmp->win, &r ); +} + +/*********** draw heading rules ***********/ +static void +draw_heading_rules( LM_DATA * lmp, int hrule_h ) +{ + if ( !( lmp->update_rows_at_top + lmp->update_rows_at_bottom ) ) + { + if ( !lmp->no_heading ) + { + int i; + XinPoint p; + +#if XIWS != XIWS_WM + int r2; + XinWindow win = lmp->win; + +#endif + +#if XIWS == XIWS_WM + /* heading rule, Release 3.0 */ + p.h = lmp->rct.left; + p.v = lmp->pix_hdr_bottom; + xi_move_to( lmp->win, p ); + p.h = hrule_h - VPIX_PER_CH; + xi_draw_line( lmp->win, p ); +#endif +#if XIWS != XIWS_WM + r2 = lmp->rct.right - lmp->delta_x; + if ( lmp->nbr_columns == 0 ) + r2 -= 2 * BORDER_WIDTH; + r2 = min( r2, hrule_h ); + WIDTHLOOP( i, BORDER_WIDTH ) + { + p.h = lmp->rct.left; + p.v = lmp->pix_row1_top - BORDER_WIDTH + i; + xi_move_to( win, p ); + p.h = r2; + xi_draw_line( win, p ); + } +#endif + } + } +} + +/*********** draw column rules ***********/ +static void +draw_column_rules( LM_DATA * lmp ) +{ + LM_COLUMN_DATA **lmcd; + int col; + XinPoint p; + +#if XIWS == XIWS_WM + XinPoint from_p; + +#endif + + if ( lmp->no_vert_lines ) + { + XinPen back_cpen; + + back_cpen = black_cpen; + back_cpen.fore_color = lmp->back_color; + XinWindowPenSet( lmp->win, &back_cpen ); + } + else + { + XinPen back_cpen; + + back_cpen = black_cpen; + back_cpen.fore_color = lmp->rule_color; + XinWindowPenSet( lmp->win, &back_cpen ); + } + for ( col = 1, lmcd = &lmp->lm_column_data[1]; col < lmp->nbr_columns; col++, ++lmcd ) + { + p.h = ( *lmcd )->x_pix_pos - RULE_WIDTH_V; +#if XIWS == XIWS_WM + p.v = lmp->pix_top; + lm_move_to( lmp, p, FALSE, TRUE ); + p.v = lmp->mlr.bottom - VPIX_PER_CH; + lm_draw_line( lmp, p, FALSE, TRUE ); +#endif +#if XIWS != XIWS_WM + /* if RULE_WIDTH_V were used, this is where it would be used */ + p.v = lmp->rct.top; + lm_move_to( lmp, p, FALSE, TRUE ); + p.v = min( lmp->rct.bottom, lmp->rrr_bottom + lmp->rrr_offset + lmp->mlr.top ); + lm_draw_line( lmp, p, FALSE, TRUE ); +#endif + } +} + +/*------------------------------------------------------------------------- +lm: current lm +update: if TRUE, draw_lm is being called due to an XinEventPaint event +-------------------------------------------------------------------------*/ +static void +draw_lm( LM lm, BOOLEAN update ) +{ + int hrule_h, + actual_r, + idx; + XinRect lmp_rct, + actual_rct, + clip_rct; + XinRect hr, + vr; + XI_OBJ *list_obj; + XI_LIST_DATA *list_data; + LM_DATA *lmp = LMP( lm ); + XinWindow win = lmp->win; + XinBrush back_cbrush; + +#if XIWS != XIWS_WM + XinRect urct; + +#else + XinBrush lm_cbrush; + XinPoint from_p; + +/***********************************************************************/ +/* set up variables for drawing */ + c_xd = C_XD; + c_xu = C_XU; + c_v = C_V; + c_xx = C_XX; +#endif + if ( !( lmp->attrib & LM_ATR_VISIBLE ) ) + { + lmp->update_rows_at_top = 0; + lmp->update_rows_at_bottom = 0; + return; + } + list_obj = lmp->list_obj; + list_data = list_obj->v.list; + lmp_rct = lmp->rct; + actual_rct = lmp_rct; +#if XIWS != XIWS_WM + if ( lmp->pixel_width ) + actual_r = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH; + else + actual_r = lmp->rct.right; + actual_rct.right = actual_r - BORDER_WIDTH; +#else + if ( lmp->pixel_width ) + actual_r = lmp->rct.left + lmp->pixel_width; + else + actual_r = lmp->rct.right + 8; + actual_rct.right = actual_r; +#endif + hrule_h = actual_r; + if ( lmp->pixel_width ) + lmp_rct.right = hrule_h; + urct = lmp_rct; + if ( list_data->sb_win ) + { + if ( list_data->have_sb_rct ) + vr = list_data->sb_rct; + else + xi_get_sb_rect( list_obj, &vr ); + urct.right = vr.right; + } + if ( list_data->hsb_win ) + { + if ( list_data->have_hsb_rct ) + hr = list_data->hsb_rct; + else + xi_get_hsb_rect( list_obj, &hr ); + urct.bottom = hr.bottom; + } +#if XIWS != XIWS_WM + if ( update && !xi_XinWindowPaintNeeds( win, &urct ) ) + { + lmp->update_rows_at_top = 0; + lmp->update_rows_at_bottom = 0; + return; + } +#endif + lmp_rct = lmp->rct; + if ( lmp->nbr_realized_rows ) + { + idx = lmp->nbr_realized_rows - 1; + lmp->rrr_bottom = lmp->pix_offsets[idx] + lmp->pix_heights[idx]; + } + else + lmp->rrr_bottom = 0; + if ( !lm_tools_inited ) + { + lm_white_cbrush.fore_color = XI_COLOR_WHITE; + lm_white_cbrush.pattern = XinBrushSolid; + lm_black_cpen.width = 1; + lm_black_cpen.fore_color = XI_COLOR_BLACK; + lm_black_cpen.pattern = XinPenSolid; + XinWindowDrawToolsNormalGet( &lm_normal_ctools ); + lm_tools_inited = TRUE; // Added by Guy :-( + } + + /***********************************************************************/ + /* draw anything other than in the cell region */ + /* prior to this, there are no calls for drawing */ + + back_cbrush = lm_white_cbrush; +/* +TO OPTIMIZE BACKGROUND DRAWING, USE THE FOLLOWING LINE, AND DON'T SET TO HOLLOW + back_cbrush.color = lmp->back_color; +*/ +#if XIWS != XIWS_WM + back_cbrush.pattern = XinBrushHollow; +#endif + XinWindowBrushSet( win, &back_cbrush ); + XinWindowPenSet( win, &lm_black_cpen ); + clip_rct = actual_rct; +#if XIWS == XIWS_WM + if ( list_data->hsb_win ) + clip_rct.bottom += 8; + clip_rct.right += 8; +#endif + xi_set_clip( win, &clip_rct ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + + /* XinBrush: white_cbrush XinDrawPen: black_cpen CLIP: actual_rct */ + + /*********** draw the rectangle around the list ***********/ + draw_list_rect( lmp, &vr, &hr ); + +#if XIWS == XIWS_WM + xi_set_clip( win, &actual_rct ); +#endif + + /*********** draw the rules between the heading and the cells ***********/ + if ( !lmp->update_cells_only ) + draw_heading_rules( lmp, hrule_h ); + + /*********** draw column rules ***********/ + draw_column_rules( lmp ); + + /* XinBrush: white_cbrush XinDrawPen: black_cpen OR back_color cpen CLIP: + * actual_rct */ + + /*********** draw column headings ***********/ + if ( !lmp->update_cells_only ) + draw_column_headings( lmp, &actual_rct ); + xi_set_clip( win, NULL ); + + /*********** draw text in cells ***********/ + draw_cells( lmp, update ); + + draw_other_rectangles( lmp, &actual_rct ); + + xi_set_clip( win, NULL ); +} + +/*------------------------------------------------------------------------- +function: send_cell_event +lm: current lm +ep: xvt event +gaining_focus: if TRUE, the edit control is gaining focus as this function is called +returns: TRUE if the event was used +-------------------------------------------------------------------------*/ +static BOOLEAN +send_cell_event( LM lm, XinEvent * ep, BOOLEAN gaining_focus, BOOLEAN send_to_txt ) +{ + BOOLEAN retval = FALSE; + int ch; + LM_DATA *lmp = LMP( lm ); + + if ( lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE ) + return FALSE; + if ( ep->type == XinEventCharacter ) + { + if ( ep->v.character.alt ) + return FALSE; + ch = ep->v.character.ch; + if ( ( ch >= ' ' || ch == XI_KEY_CLEAR || ch == XI_KEY_DEL || ch == '\b' + || ch == '\r' || ch == '\n' ) + && ch != XI_KEY_BTAB && ch != XI_KEY_UP && ch != XI_KEY_DOWN && + (!(lmp->attrib & LM_ATR_NAVIGATE) || ( ch != XI_KEY_LEFT && ch != XI_KEY_RIGHT))) + { + int focus_row, + focus_column; + BOOLEAN v_scrolled; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + retval = do_lm_cb( lm, LM_CB_CHAR, focus_row, focus_column, ep, NULL, 0 ); + /* retval = FALSE if event refused */ + if ( !retval ) + return FALSE; + } + } + + if ( send_to_txt ) + { + LM_CELL_DATA *cell_data; + int focus_row, + focus_column; + BOOLEAN v_scrolled; + BOOLEAN changed = FALSE; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + cell_data = &lmp->cell_data[focus_row][focus_column]; + if ( cell_data->button_full_cell && ep->type == XinEventCharacter ) + { + ch = ep->v.character.ch; + if ( ch == ' ' || ch == '\r' || ch == '\n' ) + { + do_lm_cb( ( LM ) lmp, LM_CB_CELL_BTN, focus_row, focus_column, ep, NULL, 0 ); + } + } + else + { + retval = xi_text_event( cell_data->xi_text, ep, gaining_focus, &changed ); + if ( changed ) + { + LM_COLUMN_DATA *lm_column_data; + + lm_column_data = lmp->lm_column_data[focus_column]; + retval = do_lm_cb( lm, LM_CB_CHANGE, focus_row, focus_column, ep, NULL, 0 ); + if ( lm_column_data->auto_tab + && ( int ) strlen( xi_text_get( cell_data->xi_text ) ) + >= lm_column_data->text_size - 1 ) + { + XinEvent ev; + + MEMCLEAR( ev ); + ev.type = XinEventCharacter; + ev.v.character.ch = '\t'; + xi_event( lmp->win, &ev ); + } + } + } + } + return retval; +} + +/*------------------------------------------------------------------------- +function: lm_vsize_hit_test +lm: current lm +ep: xvt event +rowp: row, to be filled in +columnp: column, to be filled in +returns: FALSE if hit test did not fall on place where column could be vertically sized. +-------------------------------------------------------------------------*/ +static BOOLEAN +lm_vsize_hit_test( LM_DATA * lmp, XinEvent * ep, int *rowp, int *columnp ) +{ + int i, + n, + v; + int *pix_offsetsp; + int *pix_heightsp; + + if ( lmp->lm_column_data[*columnp]->size_rows ) + { + v = ep->v.mouse.where.v - lmp->rrr_offset - lmp->mlr.top; + for ( i = 0, + pix_offsetsp = &lmp->pix_offsets[i], + pix_heightsp = &lmp->pix_heights[i]; + i < lmp->nbr_realized_rows; + ++i, ++pix_offsetsp, ++pix_heightsp ) + { + n = *pix_offsetsp + *pix_heightsp; + if ( v >= n - 3 && v <= n + 1 ) + { + *rowp = i; + return TRUE; + } + } + return FALSE; + } + else + return FALSE; +} + +/*------------------------------------------------------------------------- +function: rubber_y +lmp: current lmp +y: draw a rubber line at position y +-------------------------------------------------------------------------*/ +static void +rubber_y( LM_DATA * lmp, int y ) +{ +#if XIWS != XIWS_WM + int left, + right; + XinDrawTools new_ctools; + XinPoint pnt; + XinWindow win = lmp->win; + + left = lmp->mlr.left; + right = lmp->mlr.right; + if ( lmp->pixel_width ) + right = left + lmp->pixel_width + BORDER_WIDTH; + XinWindowDrawToolsNormalGet( &new_ctools ); + XinWindowDrawToolsSet( win, &new_ctools ); + XinWindowPenSet( win, &rubber_cpen ); + XinWindowDrawModeSet( win, XinDrawModeXor ); + xi_set_clip( win, NULL ); + pnt.h = left; + pnt.v = y; + lm_move_to( lmp, pnt, TRUE, FALSE ); + pnt.h = right; + lm_draw_line( lmp, pnt, TRUE, FALSE ); +#else + NOREF( lmp ); + NOREF( y ); +#endif +} + +/*------------------------------------------------------------------------- +function: calc_y +lmp: current lmp +ep: xvt event +returns: Calculates and returns the Y pixel position of the rubber band line. + Used only when sizing rows. +-------------------------------------------------------------------------*/ +static int +calc_y( LM_DATA * lmp, XinEvent * ep ) +{ + int row = lmp->row_being_sized; + int temp; + int min_height_in_pix = 4; + int v; + + v = min( lmp->mlr.bottom, ep->v.mouse.where.v ) - lmp->rrr_offset - lmp->mlr.top; + temp = lmp->pix_offsets[row] + min_height_in_pix; + temp = max( v, temp ); + return temp; +} + +/*------------------------------------------------------------------------- +function: lm_vsize_event +lmp: current lmp +ep: xvt event +-------------------------------------------------------------------------*/ +static void +lm_vsize_event( LM_DATA * lmp, XinEvent * ep ) +{ + int y; + + switch ( ep->type ) + { + case XinEventMouseDown: + case XinEventMouseDouble: + y = calc_y( lmp, ep ); + lmp->last_y = y; + rubber_y( lmp, y ); + break; + case XinEventMouseMove: + y = calc_y( lmp, ep ); + rubber_y( lmp, lmp->last_y ); + lmp->last_y = y; + rubber_y( lmp, y ); + break; + case XinEventMouseUp: + { + int delta, + row; + XI_OBJ row_obj; + + row = lmp->row_being_sized; + y = calc_y( lmp, ep ); + rubber_y( lmp, lmp->last_y ); + delta = y - lmp->pix_offsets[row] + 1; + XI_MAKE_ROW( &row_obj, lmp->list_obj, row ); + if ( do_lm_cb( ( LM ) lmp, LM_CB_ROW_SIZE, row, 0, NULL, NULL, delta ) ) + { + xi_set_row_height( &row_obj, delta ); + calculate_pix_offsets( lmp, FALSE ); + } + lm_focus_cell_visible_attempt( lmp ); + break; + } + default: + break; + } +} + +/*------------------------------------------------------------------------- +function: lm_select_cells_hit_test +lmp: current lmp +ep: xvt event +rowp: row number, to be filled in +columnp: column number, to be filled in +on_disabled: if TRUE, then the hit was on a disabled column +returns: TRUE if there was a hit +-------------------------------------------------------------------------*/ +static BOOLEAN +lm_select_cells_hit_test( LM_DATA * lmp, XinEvent * ep, int *rowp, + int *columnp, BOOLEAN * on_disabled ) +{ + int delta_top, + column, + col_offset, + last_vis, + row, + idx; + LM_COLUMN_DATA *column_data; + BOOLEAN retval; + BOOLEAN inv_v, + inv_h; /* if set to TRUE, then invalid v or invalid h */ + + retval = TRUE; + if ( columnp ) + *columnp = 0; + if ( on_disabled ) + *on_disabled = FALSE; + inv_v = FALSE; + inv_h = FALSE; + last_vis = lmp->last_vis; + delta_top = ep->v.mouse.where.v - lmp->mlr.top - lmp->rrr_offset; + + /* If list has no columns */ + if ( lmp->nbr_columns <= 0 ) + return FALSE; + + /* If mouse is above the top of the first row */ + if ( ep->v.mouse.where.v < lmp->pix_row1_top - RULE_WIDTH_V - + RULE_Y_OFFSET_TOP ) + { + if ( rowp ) + *rowp = 0; + retval = FALSE; + inv_v = TRUE; + } + + /* if mouse is below the bottom of the list, or if the mouse is below the + * bottom of the last row if there are fewer rows than can be displayed in + * the list */ + idx = lmp->nbr_realized_rows - 1; + if ( ep->v.mouse.where.v >= lmp->mlr.bottom || + delta_top > lmp->pix_offsets[idx] + lmp->pix_heights[idx] ) + { + if ( rowp ) + *rowp = lmp->nbr_realized_rows; + retval = FALSE; + inv_v = TRUE; + } + + /* if mouse is to the right of the list, or if the mouse is to the right of + * the rightmost column */ + column_data = lmp->lm_column_data[lmp->nbr_columns - 1]; + if ( ( ep->v.mouse.where.h >= ( lmp->rct.right - lmp->rct.left ) ) || + ( ep->v.mouse.where.h >= ( column_data->x_pix_pos + column_data->pix_width ) ) ) + { + if ( columnp ) + *columnp = last_vis + 1; + retval = FALSE; + inv_h = TRUE; + } + + /* if mouse has a valid y coordinate */ + if ( !inv_v ) + { + + if ( rowp ) + *rowp = 0; + retval = FALSE; + for ( row = 0; row < lmp->nbr_realized_rows; ++row ) + { + int pix_offset, + pix_height; + + pix_offset = lmp->pix_offsets[row]; + pix_height = lmp->pix_heights[row]; + if ( delta_top >= pix_offset - SELECT_CELLS_OFFSET - 2 + && delta_top <= pix_offset + SELECT_CELLS_OFFSET ) + { + if ( rowp ) + *rowp = row; + if ( !inv_h ) + retval = TRUE; + break; + } + if ( delta_top >= ( pix_offset + pix_height ) - SELECT_CELLS_OFFSET - 2 + && delta_top <= ( pix_offset + pix_height ) + SELECT_CELLS_OFFSET ) + { + if ( rowp ) + *rowp = row + 1; + if ( !inv_h ) + retval = TRUE; + break; + } + if ( delta_top >= pix_offset && + delta_top <= pix_offset + pix_height ) + { + if ( rowp ) + *rowp = row; + } + } + if ( rowp && !retval && *rowp < lmp->down_row ) + ++* rowp; + } + + /* if mouse has a valid x coordinate */ + if ( !inv_h ) + { + column_data = lmp->lm_column_data[0]; + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + if ( ( ( !( column_data->attrib & XI_ATR_ENABLED ) || lmp->down_on_disabled ) && + ( !( column_data->attrib & XI_ATR_SELECTABLE ) ) ) && + ( ( ep->v.mouse.where.h >= column_data->x_pix_pos ) && + ( ep->v.mouse.where.h < ( column_data->x_pix_pos + column_data->pix_width ) ) ) ) + { + if ( columnp ) + *columnp = 0; + if ( on_disabled ) + *on_disabled = TRUE; + } + else if ( ( ep->v.mouse.where.h >= column_data->x_pix_pos ) && + ( ep->v.mouse.where.h < ( column_data->x_pix_pos + col_offset ) ) ) + { + if ( columnp ) + *columnp = 0; + } + else + { + BOOLEAN found = FALSE; + int last_col; + + last_col = -1; + for ( column = 0; column < lmp->nbr_columns; column++ ) + { + int temp; + + column_data = lmp->lm_column_data[column]; + if ( ( ( !( column_data->attrib & XI_ATR_ENABLED ) || lmp->down_on_disabled ) && + ( !( column_data->attrib & XI_ATR_SELECTABLE ) ) ) && + ( ( ep->v.mouse.where.h >= column_data->x_pix_pos ) && + ( ep->v.mouse.where.h < + ( column_data->x_pix_pos + column_data->pix_width ) ) ) ) + { + if ( columnp ) + *columnp = column; + if ( on_disabled ) + *on_disabled = TRUE; + found = TRUE; + break; + } + temp = column_data->x_pix_pos + + col_offset + + column_data->pix_width - SELECT_CELLS_OFFSET; + if ( ep->v.mouse.where.h >= temp && + ep->v.mouse.where.h < ( temp + col_offset * 2 + + 2 * SELECT_CELLS_OFFSET + + RULE_WIDTH_V ) ) + { + if ( columnp ) + *columnp = column + 1; + found = TRUE; + break; + } + if ( ep->v.mouse.where.h >= temp ) + last_col = column; + } + if ( !found ) + { + retval = FALSE; + if ( columnp ) + { + if ( ( last_col + 1 ) < lmp->down_column ) + *columnp = last_col + 2; + else + *columnp = last_col + 1; + } + } + } + } + /* If v is not invalid, and if h is not invalid, and if the column is valid, + * then if the column is enabled, then the hit test must be within a range of + * the rules. If the column is not enabled, then the hit test may be anywhere + * within the cell. */ + if ( !inv_v ) + { + BOOLEAN enabled_col = FALSE; + + if ( columnp && !inv_h ) + { + if ( *columnp >= lmp->nbr_columns ) + enabled_col = FALSE; + else + enabled_col = ( lmp->lm_column_data[*columnp]->attrib & XI_ATR_ENABLED && + !lmp->down_on_disabled ); + if ( enabled_col ) + { + delta_top = ep->v.mouse.where.v - lmp->mlr.top - lmp->rrr_offset; + retval = FALSE; + for ( row = 0; row < lmp->nbr_realized_rows; ++row ) + { + int pix_offset, + pix_height; + + pix_offset = lmp->pix_offsets[row]; + pix_height = lmp->pix_heights[row]; + if ( delta_top >= pix_offset - SELECT_CELLS_OFFSET - 2 + && delta_top <= pix_offset + SELECT_CELLS_OFFSET ) + { + if ( rowp ) + *rowp = row; + retval = TRUE; + break; + } + if ( delta_top >= ( pix_offset + pix_height ) - SELECT_CELLS_OFFSET - 2 + && delta_top <= ( pix_offset + pix_height ) + SELECT_CELLS_OFFSET ) + { + if ( rowp ) + *rowp = row + 1; + retval = TRUE; + break; + } + } + return retval; + } + } + } + return retval; +} + +/*------------------------------------------------------------------------- +function: invert_selection +lmp: current lmp +r: row +c: column +-------------------------------------------------------------------------*/ +static void +invert_selection( LM_DATA * lmp, int r, int c, BOOLEAN v_scrolled ) +{ + unsigned long attrib; + + attrib = lm_get_attrib( ( LM ) lmp, LM_CELL, r, c, v_scrolled ); + if ( attrib & LM_CELL_ATR_SELECTED ) + lm_set_attrib( ( LM ) lmp, LM_CELL, r, c, v_scrolled, + attrib & ~LM_CELL_ATR_SELECTED, FALSE ); + else + lm_set_attrib( ( LM ) lmp, LM_CELL, r, c, v_scrolled, + attrib | LM_CELL_ATR_SELECTED, FALSE ); +} + +/*------------------------------------------------------------------------- +function: in_rct +rct: rectangle +r: row +c: column +returns: TRUE if c and r are in rct +-------------------------------------------------------------------------*/ +static BOOLEAN +in_rct( XinRect * rct, int r, int c ) +{ + if ( c >= rct->left && c < rct->right && r >= rct->top && r < rct->bottom ) + return TRUE; + return FALSE; +} + +/*------------------------------------------------------------------------- +function: lm_select_cell_event +lmp: current lmp +ep: xvt event +-------------------------------------------------------------------------*/ +static void +lm_select_cell_event( LM_DATA * lmp, XinEvent * ep ) +{ + int row, + column; + + switch ( ep->type ) + { + case XinEventMouseDown: + case XinEventMouseDouble: + if ( !ep->v.mouse.shift ) + { + int r, + c; + + for ( r = 0; r < lmp->nbr_realized_rows; ++r ) + for ( c = 0; c < lmp->nbr_columns; ++c ) + { + unsigned long attrib; + + attrib = lm_get_attrib( ( LM ) lmp, LM_CELL, r, c, FALSE ); + if ( attrib & LM_CELL_ATR_SELECTED ) + lm_set_attrib( ( LM ) lmp, LM_CELL, r, c, FALSE, + attrib & ~LM_CELL_ATR_SELECTED, FALSE ); + } + } + break; + case XinEventMouseMove: + case XinEventMouseUp: + { + int last_cur_row, + last_cur_column, + r, + c, + down_row, + down_column; + XinRect old_rct, + new_rct, + enclosing_rct; + + lm_select_cells_hit_test( lmp, ep, &row, &column, NULL ); + last_cur_row = lmp->cur_row; + last_cur_column = lmp->cur_column; + down_row = lmp->down_row; + down_column = lmp->down_column; + if ( lmp->down_on_disabled ) + { + if ( ep->type == XinEventMouseUp ) + lmp->down_on_disabled = FALSE; + if ( row >= lmp->down_row ) + lmp->cur_row = row + 1; + else + lmp->cur_row = row; + if ( column >= lmp->down_column ) + lmp->cur_column = column + 1; + else + lmp->cur_column = column; + } + else + { + lmp->cur_row = row; + lmp->cur_column = column; + } + if ( lmp->cur_row == last_cur_row && lmp->cur_column == last_cur_column && + ( ep->type == XinEventMouseMove || ep->type == XinEventMouseUp ) ) + break; + old_rct.left = min( down_column, last_cur_column ); + old_rct.right = max( down_column, last_cur_column ); + old_rct.top = min( down_row, last_cur_row ); + old_rct.bottom = max( down_row, last_cur_row ); + new_rct.left = min( down_column, lmp->cur_column ); + new_rct.right = max( down_column, lmp->cur_column ); + new_rct.top = min( down_row, lmp->cur_row ); + new_rct.bottom = max( down_row, lmp->cur_row ); + enclosing_rct.top = min( old_rct.top, new_rct.top ); + enclosing_rct.bottom = max( old_rct.bottom, new_rct.bottom ); + enclosing_rct.left = min( old_rct.left, new_rct.left ); + enclosing_rct.right = max( old_rct.right, new_rct.right ); + for ( c = enclosing_rct.left; c <= enclosing_rct.right; ++c ) + { + for ( r = enclosing_rct.top; r <= enclosing_rct.bottom; ++r ) + { + if ( ( in_rct( &old_rct, r, c ) && + in_rct( &new_rct, r, c ) ) || + ( !in_rct( &old_rct, r, c ) && + !in_rct( &new_rct, r, c ) ) ) + continue; + if ( r >= lmp->nbr_realized_rows || c >= lmp->nbr_columns || + r < 0 || c < 0 ) + continue; + invert_selection( lmp, r, c, FALSE ); + } + } + } + break; + default: + break; + } +} + +/*------------------------------------------------------------------------- +function: lm_event +lm: current lm +ep: xvt event +return: TRUE if event is consumed +-------------------------------------------------------------------------*/ +#define DRAG_MARGIN 5 + +int +lm_event( XI_OBJ * itf, LM lm, XinEvent * ep ) +{ + int row, + column; + LM_DATA *lmp = LMP( lm ); + BOOLEAN send_event = FALSE; + int retval = 1; + XinEvent oevt; + BOOLEAN ep_needs_restore = FALSE; + + oevt = *ep; + switch ( ep->type ) + { + case XinEventMouseDown: + case XinEventMouseDouble: + case XinEventMouseMove: + case XinEventMouseUp: + { + XinRect rct; + + if ( lmp->attrib & XI_ATR_VISIBLE ) + { + /* COORDINATE CONVERSION changes horizontal coordinates - moves mouse + * to the right - increases where.h if where.h is > lmp->vir_left, so + * that where.h is in the correct virtual horizontal space - also + * makes where.h be relative to the list, not the window. */ + lm_get_rect( lm, LM_LIST, 0, &rct ); + if ( xi_pt_in_rect( &rct, ep->v.mouse.where ) || + lmp->selecting_cells || lmp->sizing_column || lmp->moving_column || + lmp->down_in_btn || lmp->selecting_text || lmp->sizing_row || + lmp->dragging_row || lmp->down_in_heading ) + { + if ( ep->type == XinEventMouseDown ) + { + if ( ep->v.mouse.where.h >= lmp->vir_left ) + lmp->down_in_hscrolling = TRUE; + else + lmp->down_in_hscrolling = FALSE; + } + if ( !lmp->sizing_column ) + { + if ( ( lmp->pixel_width && ( ep->v.mouse.where.h >= lmp->vir_left ) ) ) + { + ep->v.mouse.where.h += lmp->delta_x; + lmp->in_hscrolling = TRUE; + } + else + lmp->in_hscrolling = FALSE; + } + else + { + if ( lmp->down_in_hscrolling ) + ep->v.mouse.where.h += lmp->delta_x; + } + ep->v.mouse.where.h -= lmp->rct.left; + ep_needs_restore = TRUE; + } + else + { + *ep = oevt; + return FALSE; + } + } + else + { + *ep = oevt; + return FALSE; + } + break; + } + default: + break; + } + switch ( ep->type ) + { + case XinEventPaint: + /* the following code sends the event directly on to redraw_cell if text + * is being scrolled in a text object. This speeds horizontal scrolling. + * see also lm_text_scrolling. */ + if ( lmp->text_scrolling ) + { + int row, + col; + BOOLEAN v_scrolled; + + lm_focus_cell_get( lmp, &row, &col, &v_scrolled ); + draw_cell_range( lmp, row, row, col, col, FALSE ); + if ( lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE ) + send_cell_event( lm, &oevt, FALSE, TRUE ); + lmp->text_scrolling = FALSE; + } + else + { + draw_lm( lm, TRUE ); + /* if ( lm_focus_state_get(lmp) != LM_FOCUS_VISIBLE ) */ + send_cell_event( lm, &oevt, FALSE, TRUE ); + } + retval = 0; + break; + case XinEventResize: + { + int new_height, + new_width; + XinRect hr, + vr, + cr; + XI_OBJ *list_obj; + + if ( lmp->resize_with_window ) + { + XinRect rct, + wrct; + BOOLEAN replace_focus = FALSE; + + list_obj = lmp->list_obj; + if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + lm_focus_cell_invis_make( lmp ); + else + { + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + { + XI_OBJ *focus_obj = xi_get_focus(list_obj->itf); + if (focus_obj->type == XIT_CELL && focus_obj->parent == list_obj) + replace_focus = TRUE; + if ( !xi_move_focus( list_obj->itf ) ) + { + retval = 0; + break; + } + } + } + xi_get_hsb_rect( list_obj, &hr ); + xi_get_sb_rect( list_obj, &vr ); + XinWindowRectGet( lmp->win, &cr ); + new_height = cr.bottom - lmp->pix_top; + new_width = cr.right - lmp->rct.left; + xi_set_list_size( list_obj, new_height, new_width ); + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_LIMIT_MIN_WIN_SIZE ) ) + { + xi_get_rect( list_obj, &rct ); + if ( abs( rct.bottom - cr.bottom ) > 4 || + abs( rct.right - cr.right ) > 4 ) + { + wrct = cr; + wrct.bottom = max( rct.bottom, cr.bottom ); + wrct.right = max( rct.right, cr.right ); + if ( wrct.bottom != cr.bottom || wrct.right != cr.right ) + { + XinWindowPointsTranslate( lmp->win, XinWindowParentGet( lmp->win ), ( XinPoint * ) & wrct, 2 ); + XinWindowRectSet( lmp->win, &wrct ); + } + } + } + if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + lm_focus_cell_visible_attempt( lmp ); + else if (replace_focus) + xi_move_focus( list_obj ); + } + retval = 0; + break; + } + case XinEventMouseDown: + case XinEventMouseDouble: + { + int hit_test_value; + BOOLEAN is_vis, + is_hit, + is_part_vis; + + if ( ep->v.mouse.button > 0 ) + break; + + if ( lmp->single_select && lmp->position_by_typing_cid > 0 && lmp->position_by_typing_buf != NULL ) + lmp->position_by_typing_buf[0] = '\0'; + + hit_test_value = lm_hit_test( lm, ep, &oevt, &row, &column, &is_vis, &is_hit, &is_part_vis ); + /* The row scrolled during the XinEventMouseDown */ + if ( is_part_vis && ep->type == XinEventMouseDouble ) + --row; + if ( is_part_vis && ep->type != XinEventMouseDouble ) + { + XinEvent lep; + LM_SCROLL_ARG lm_scroll_arg; + static BOOLEAN in_here = FALSE; + + if ( in_here ) + return FALSE; + MEMCLEAR( lm_scroll_arg ); + lm_scroll_arg.lm = lm; + lm_scroll_arg.nbr_lines = 1; + /* lm_scroll_arg.percent = 0; lm_scroll_arg.same_cell = 0; + * lm_scroll_arg.rec = 0L; lm_scroll_arg.have_rec = FALSE; + * lm_scroll_arg.color = 0L; lm_scroll_arg.attrib = 0L; + * lm_scroll_arg.row_height = 0; lm_scroll_arg.rec_at_top = FALSE; */ + + lm_focus_cell_invis_make( lmp ); + calculate_pix_offsets( lmp, TRUE ); + lm_make_rrr_room_pix( lmp, 0, FALSE ); + lm_focus_cell_visible_attempt( lmp ); + + lm_scroll( &lm_scroll_arg ); + lep = oevt; + lep.v.mouse.where.v -= lm_scroll_arg.pixels_scrolled; + in_here = TRUE; + lm_event( itf, lm, &lep ); + in_here = FALSE; + return TRUE; + } + if ( is_hit ) + { + if ( lm_vsize_hit_test( lmp, ep, &row, &column ) ) + { + XI_OBJ *itf, + *list; + + itf = lmp->itf_obj; + list = lmp->list_obj; + if ( list && xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + { + lm_focus_cell_invis_make( lmp ); + xi_set_trap_obj( list ); + lmp->row_being_sized = row; + lmp->sizing_row = TRUE; + XinWindowMouseTrap( lmp->win, TRUE ); + lm_vsize_event( lmp, ep ); + } + else + { + if ( list && xi_move_focus( itf ) ) + { + xi_set_trap_obj( list ); + lmp->row_being_sized = row; + lmp->sizing_row = TRUE; + XinWindowMouseTrap( lmp->win, TRUE ); + lm_vsize_event( lmp, ep ); + } + } + break; + } + + } + + if ( lmp->select_cells ) + { + int row, + column; + BOOLEAN on_disabled; + + if ( lm_select_cells_hit_test( lmp, ep, &row, &column, &on_disabled ) ) + { + XI_OBJ *list; + + list = lmp->list_obj; + xi_set_trap_obj( list ); + lmp->selecting_cells = TRUE; + lmp->down_row = row; + lmp->cur_row = row; + lmp->down_column = column; + lmp->cur_column = column; + lmp->down_on_disabled = on_disabled; + lm_select_cell_event( lmp, ep ); + XinWindowMouseTrap( lmp->win, TRUE ); + if ( on_disabled ) + { + invert_selection( lmp, row, column, FALSE ); + lmp->cur_row = row + 1; + lmp->cur_column = column + 1; + } + break; + } + } + + /* check for cell button hit */ + if ( hit_test_value == 5 ) + if ( LIST_IS_ENABLED( lm ) ) + lm_cell_btn_event( lmp, ep, &oevt ); + + /* check for focus acquisition */ + if ( hit_test_value == 1 ) + { + if ( row == -1 ) + { + if ( LIST_IS_ENABLED( lm ) && + COLUMN_IS_SELECTABLE( lm, column ) && + ( ep->type == XinEventMouseDouble || + ( ep->type == XinEventMouseDown && ! + lmp->movable_columns && !xi_get_pref( XI_PREF_SINGLE_CLICK_COL_SELECT ) ) + ) ) + { + unsigned long attrib; + LM_CB_DATA lm_cb_data; + + attrib = lm_get_attrib( lm, LM_COLUMN, column, 0, FALSE ); + if ( ep->type == XinEventMouseDouble && !lmp->movable_columns ) + attrib |= LM_COL_ATR_SELECTED; + else + { + if ( attrib & LM_COL_ATR_SELECTED ) + attrib &= ~LM_COL_ATR_SELECTED; + else + attrib |= LM_COL_ATR_SELECTED; + } + lm_cb_data.lm = lm; + lm_cb_data.cb_type = LM_CB_SELECT; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) 255; + lm_cb_data.column = ( unsigned char ) column; + lm_cb_data.v.select.selected = + ( ( attrib & LM_COL_ATR_SELECTED ) != 0 ); + lm_cb_data.v.select.dbl_click = + ( ep->type == XinEventMouseDouble ); + lm_cb_data.v.select.shift = ep->v.mouse.shift; + lm_cb_data.v.select.control = ep->v.mouse.control; + ( *lmp->lm_cb ) ( &lm_cb_data ); + if ( !lm_cb_data.v.select.refused ) + lm_set_attrib( lm, LM_COLUMN, column, 0, FALSE, attrib, + FALSE ); + } + else if ( LIST_IS_ENABLED( lm ) && + COLUMN_IS_SELECTABLE( lm, column ) && + ( ep->type == XinEventMouseDouble || + ( ep->type == XinEventMouseDown && + !lmp->movable_columns && xi_get_pref( XI_PREF_SINGLE_CLICK_COL_SELECT ) ) + ) ) + { /* Select on the mouse up if the mouse is still + * in the heading. */ + XinRect rct; + + lmp->down_in_heading = TRUE; + lmp->column_being_moved = column; + lmp->down_pt = ep->v.mouse.where; + lmp->lm_column_data[column]->pushed = TRUE; + xi_set_trap_obj( lmp->list_obj ); + XinWindowMouseTrap( lmp->win, TRUE ); + lm_get_rect( lm, LM_COLUMN, column, &rct ); + draw_column_headings( lmp, &rct ); + } + + if ( LIST_IS_ENABLED( lm ) && COLUMN_IS_SELECTABLE( lm, column ) && + ep->type == XinEventMouseDown && lmp->movable_columns && + xi_get_pref( XI_PREF_SINGLE_CLICK_COL_SELECT ) ) + { + /* If the mouse doesn't move much, we will select on the up. If + * it does move, we will do a column move. */ + XinRect rct; + + lmp->down_in_heading = TRUE; + lmp->column_being_moved = column; + lmp->down_pt = ep->v.mouse.where; + lmp->lm_column_data[column]->pushed = TRUE; + xi_set_trap_obj( lmp->list_obj ); + XinWindowMouseTrap( lmp->win, TRUE ); + lm_get_rect( lm, LM_COLUMN, column, &rct ); + draw_column_headings( lmp, &rct ); + } + else if ( LIST_IS_ENABLED( lm ) && + ( ep->type == XinEventMouseDown || + ( ep->type == XinEventMouseDouble && + !COLUMN_IS_SELECTABLE( lm, column ) ) ) && + lmp->movable_columns ) + { + XI_OBJ *itf, + *list; + + itf = lmp->itf_obj; + list = lmp->list_obj; + if ( list && xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + { + lm_focus_cell_invis_make( lmp ); + xi_set_trap_obj( list ); + lmp->column_being_moved = column; + lmp->moving_column = TRUE; + XinWindowMouseTrap( lmp->win, TRUE ); + lm_move_event( lmp, ep ); + } + else + { + if ( list && xi_move_focus( itf ) ) + { + xi_set_trap_obj( list ); + lmp->column_being_moved = column; + lmp->moving_column = TRUE; + XinWindowMouseTrap( lmp->win, TRUE ); + lm_move_event( lmp, ep ); + } + } + } + break; + } + + if ( CELL_IS_SELECTABLE( lm, row, column ) ) + { + lmp->down_pt = ep->v.mouse.where; + lmp->rec_being_moved = lmp->recs[row]; + lmp->drag_row_height = lmp->pix_heights[row]; + lmp->down_in_row = TRUE; + xi_set_trap_obj( lmp->list_obj ); + if ( lmp->single_select ) + { + lmp->list_obj->v.list->in_select_process = TRUE; + xi_move_focus( lmp->list_obj ); + select_row( lm, row, column, ( BOOLEAN ) ( ep->type == XinEventMouseDouble ) ); + if ( xi_is_itf( itf ) ) + lmp->list_obj->v.list->in_select_process = FALSE; + } + else + { + unsigned long attrib; + attrib = lm_get_attrib( lm, LM_ROW, row, 0, FALSE ); + if ( lmp->drag_and_drop_rows && ( attrib & LM_ROW_ATR_SELECTED ) != 0 + && !ep->v.mouse.shift ) + { + lmp->delay_select = TRUE; + lmp->delay_row = row; + lmp->delay_column = column; + lmp->delay_dbl = (ep->type == XinEventMouseDouble); + } + else + send_select_event( lm, row, column, ep, attrib ); + } + } + else + { + BOOLEAN gaining_focus = FALSE; + LM_CELL_DATA *cell_data = &lmp->cell_data[row][column]; + + if ( !is_vis ) + break; + + if ( !cell_data->icon_rid && cell_data->bitmap == NULL && + !cell_data->button_full_cell ) + { + /* set this flag here, not later! */ + lmp->have_mouse = TRUE; + + if ( lm_focus_state_get( lmp ) == LM_FOCUS_NOWHERE ) + { + send_event = do_lm_cb( lm, LM_CB_FOCUS, row, column, + NULL, NULL, 0 ); + gaining_focus = TRUE; + } + else + { + if ( !lm_focus_cell_has( lmp, row, column, FALSE ) ) + { + send_event = do_lm_cb( lm, LM_CB_FOCUS, row, column, NULL, NULL, 0 ); + /* send_event = FALSE if refused */ + + gaining_focus = send_event; + } + else + send_event = TRUE; + } + if ( send_event ) + { + int focus_row, + focus_column; + BOOLEAN v_scrolled; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + if ( ( lmp->lm_column_data[focus_column]->attrib + & LM_COL_ATR_AUTOSELECT ) + && xi_get_pref( XI_PREF_AUTOSEL_ON_MOUSE ) + && gaining_focus ) + ; + else + { + XinWindowMouseTrap( lmp->win, TRUE ); + lmp->selecting_text = TRUE; + send_cell_event( lm, &oevt, gaining_focus, TRUE ); + } + } + else + lmp->have_mouse = FALSE; + if ( ep->type == XinEventMouseDouble ) + do_lm_cb( lm, LM_CB_DBL, row, column, NULL, NULL, 0 ); + } + } + } + else + { + if ( LIST_IS_ENABLED( lm ) && + lmp->sizable_columns && + lm_size_hit_test( lm, ep, &column ) ) + { + XI_OBJ *itf, + *list; + + itf = lmp->itf_obj; + list = lmp->list_obj; + if ( list && xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + { + lm_focus_cell_invis_make( lmp ); + xi_set_trap_obj( list ); + lmp->column_being_sized = column; + lmp->sizing_column = TRUE; + XinWindowMouseTrap( lmp->win, TRUE ); + lm_size_event( lmp, ep ); + } + else + { + if ( list && xi_move_focus( itf ) ) + { + xi_set_trap_obj( list ); + lmp->column_being_sized = column; + lmp->sizing_column = TRUE; + XinWindowMouseTrap( lmp->win, TRUE ); + lm_size_event( lmp, ep ); + } + } + } + else + retval = 0; + } + break; + } + case XinEventMouseUp: + lmp->down_in_row = FALSE; + if ( lmp->single_select && lmp->position_by_typing_cid > 0 && lmp->position_by_typing_buf != NULL ) + lmp->position_by_typing_buf[0] = '\0'; + if ( lmp->selecting_cells ) + { + LM_CB_DATA lm_cb_data; + + lm_select_cell_event( lmp, ep ); + XinWindowMouseRelease( ); + lmp->selecting_cells = FALSE; + lmp->down_row = 0; + lmp->down_column = 0; + lm_cb_data.lm = lm; + lm_cb_data.cb_type = LM_CB_SELECT; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) 255; + lm_cb_data.column = ( unsigned char ) 255; + lm_cb_data.v.select.selected = TRUE; + lm_cb_data.v.select.dbl_click = FALSE; + lm_cb_data.v.select.shift = ep->v.mouse.shift; + lm_cb_data.v.select.control = ep->v.mouse.control; + ( *lmp->lm_cb ) ( &lm_cb_data ); + } + if ( lmp->sizing_column ) + { + lm_size_event( lmp, ep ); + XinWindowMouseRelease( ); + lmp->sizing_column = FALSE; + lmp->column_being_sized = 0; + break; + } + if ( lmp->sizing_row ) + { + lm_vsize_event( lmp, ep ); + XinWindowMouseRelease( ); + lmp->sizing_row = FALSE; + lmp->row_being_sized = 0; + break; + } + if ( lmp->moving_column ) + { + lm_move_event( lmp, ep ); + XinWindowMouseRelease( ); + lmp->moving_column = FALSE; + lmp->column_being_moved = 0; + break; + } + if ( lmp->down_in_btn ) + { + lm_cell_btn_event( lmp, ep, &oevt ); + XinWindowMouseRelease( ); + lmp->down_in_btn = FALSE; + lmp->btn_down = FALSE; + break; + } + if ( lmp->dragging_row ) + { + lm_drag_row_event( itf, lmp, ep, &oevt ); + XinWindowMouseRelease( ); + lmp->dragging_row = FALSE; + break; + } + if ( lmp->delay_select ) + { + unsigned long attrib = lm_get_attrib( lm, LM_ROW, lmp->delay_row, 0, FALSE ); + + lmp->delay_select = FALSE; + if (lmp->delay_dbl) + { + XinEvent ev; + MEMCLEAR( ev ); + ev.type = XinEventMouseDouble; + lmp->delay_dbl = FALSE; + send_select_event( lm, lmp->delay_row, lmp->delay_column, &ev, attrib ); + } + else + send_select_event( lm, lmp->delay_row, lmp->delay_column, ep, attrib ); + break; + } + if ( lmp->down_in_heading ) + { + /* If the mouse is still in the heading, select the col. */ + int hit_test_value; + BOOLEAN is_vis, + is_hit, + is_part_vis; + unsigned long attrib; + LM_CB_DATA lm_cb_data; + + lmp->lm_column_data[lmp->column_being_moved]->pushed = FALSE; + hit_test_value = lm_hit_test( lm, ep, &oevt, &row, &column, &is_vis, + &is_hit, &is_part_vis ); + if ( hit_test_value == 1 && row == -1 && column == lmp->column_being_moved ) + { + attrib = lm_get_attrib( lm, LM_COLUMN, column, 0, FALSE ); + if ( attrib & LM_COL_ATR_SELECTED ) + attrib &= ~LM_COL_ATR_SELECTED; + else + attrib |= LM_COL_ATR_SELECTED; + lm_cb_data.lm = lm; + lm_cb_data.cb_type = LM_CB_SELECT; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) 255; + lm_cb_data.column = ( unsigned char ) lmp->column_being_moved; + lm_cb_data.v.select.selected = + ( ( attrib & LM_COL_ATR_SELECTED ) != 0 ); + lm_cb_data.v.select.dbl_click = FALSE; + lm_cb_data.v.select.shift = ep->v.mouse.shift; + lm_cb_data.v.select.control = ep->v.mouse.control; + ( *lmp->lm_cb ) ( &lm_cb_data ); + if ( !lm_cb_data.v.select.refused ) + lm_set_attrib( lm, LM_COLUMN, column, 0, FALSE, attrib, + FALSE ); + } + else + { + XinRect rct; + + lm_get_rect( lm, LM_COLUMN, lmp->column_being_moved, &rct ); + draw_column_headings( lmp, &rct ); + } + XinWindowMouseRelease( ); + lmp->down_in_heading = FALSE; + lmp->column_being_moved = 0; + break; + } + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + { + send_cell_event( lm, &oevt, FALSE, TRUE ); + lmp->selecting_text = FALSE; + XinWindowMouseRelease( ); + lmp->have_mouse = FALSE; + break; + } + break; + case XinEventMouseMove: + { + BOOLEAN is_vis, + is_hit, + is_part_vis; + + if ( !( lmp->attrib & XI_ATR_VISIBLE ) ) + { + retval = FALSE; + break; + } + if ( lmp->selecting_cells ) + { + lm_select_cell_event( lmp, ep ); + break; + } + if ( lmp->sizing_column ) + { + lm_size_event( lmp, ep ); + break; + } + if ( lmp->sizing_row ) + { + lm_vsize_event( lmp, ep ); + break; + } + if ( lmp->moving_column ) + { + lm_move_event( lmp, ep ); + break; + } + if ( lmp->down_in_btn ) + { + lm_cell_btn_event( lmp, ep, &oevt ); + break; + } + if ( lmp->dragging_row ) + { + lm_drag_row_event( itf, lmp, ep, &oevt ); + break; + } + if ( lmp->down_in_row && lmp->drag_and_drop_rows + && ( ep->v.mouse.where.v > lmp->down_pt.v + DRAG_MARGIN + || ep->v.mouse.where.v < lmp->down_pt.v - DRAG_MARGIN + || ep->v.mouse.where.h > lmp->down_pt.h + DRAG_MARGIN + || ep->v.mouse.where.h < lmp->down_pt.h - DRAG_MARGIN ) ) + { /* start row dragging */ + lmp->down_in_row = FALSE; + lmp->delay_select = FALSE; + XinWindowMouseTrap( lmp->win, TRUE ); + lm_drag_row_event( itf, lmp, ep, &oevt ); + } + if ( lmp->down_in_heading && lmp->movable_columns + && ( ep->v.mouse.where.v > lmp->down_pt.v + DRAG_MARGIN + || ep->v.mouse.where.v < lmp->down_pt.v - DRAG_MARGIN + || ep->v.mouse.where.h > lmp->down_pt.h + DRAG_MARGIN + || ep->v.mouse.where.h < lmp->down_pt.h - DRAG_MARGIN ) ) + { + /* The user moved far enough to switch to moving the column. */ + XI_OBJ *itf, + *list; + XinPoint where; + XinRect rct; + + lmp->down_in_heading = FALSE; + lmp->lm_column_data[lmp->column_being_moved]->pushed = FALSE; + lm_get_rect( lm, LM_COLUMN, lmp->column_being_moved, &rct ); + draw_column_headings( lmp, &rct ); + itf = lmp->itf_obj; + list = lmp->list_obj; + if ( list && xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) ) + { + lm_focus_cell_invis_make( lmp ); + lmp->moving_column = TRUE; + ep->type = XinEventMouseDown; + where = ep->v.mouse.where; + ep->v.mouse.where = lmp->down_pt; + lm_move_event( lmp, ep ); + ep->type = XinEventMouseMove; + ep->v.mouse.where = where; + lm_move_event( lmp, ep ); + } + else + { + if ( list && xi_move_focus( itf ) ) + { + lmp->moving_column = TRUE; + ep->type = XinEventMouseDown; + where = ep->v.mouse.where; + ep->v.mouse.where = lmp->down_pt; + lm_move_event( lmp, ep ); + ep->type = XinEventMouseMove; + ep->v.mouse.where = where; + lm_move_event( lmp, ep ); + } + else + lmp->column_being_moved = 0; + } + break; + } + else + { + int hit_test_value; + BOOLEAN is_vis, + is_hit, + is_part_vis; + + hit_test_value = lm_hit_test( lm, ep, &oevt, &row, &column, &is_vis, + &is_hit, &is_part_vis ); + if ( lmp->down_in_heading && !lmp->movable_columns && + lmp->lm_column_data[lmp->column_being_moved]->pushed == TRUE && + ( hit_test_value != 1 || row != -1 || column != lmp->column_being_moved ) ) + { + XinRect rct; + + lmp->lm_column_data[lmp->column_being_moved]->pushed = FALSE; + lm_get_rect( lm, LM_COLUMN, lmp->column_being_moved, &rct ); + draw_column_headings( lmp, &rct ); + } + else if ( lmp->down_in_heading && !lmp->movable_columns && + lmp->lm_column_data[lmp->column_being_moved]->pushed == FALSE && + ( hit_test_value == 1 && row == -1 && column == lmp->column_being_moved ) ) + { + XinRect rct; + + lmp->lm_column_data[lmp->column_being_moved]->pushed = TRUE; + lm_get_rect( lm, LM_COLUMN, lmp->column_being_moved, &rct ); + draw_column_headings( lmp, &rct ); + } + } + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + send_cell_event( lm, &oevt, FALSE, TRUE ); + retval = lm_hit_test( lm, ep, &oevt, &row, &column, &is_vis, &is_hit, &is_part_vis ); + if ( is_part_vis ) + { + unsigned long attrib; + + attrib = lmp->lm_column_data[column]->attrib; + if ( attrib & XI_ATR_SELECTABLE ) + return 0; + if ( !retval ) + retval = 1; + return retval; + } + if ( is_hit ) + { + if ( LIST_IS_ENABLED( lm ) && + lm_vsize_hit_test( lmp, ep, &row, &column ) ) + { + *ep = oevt; + return 6; + } + } + if ( LIST_IS_ENABLED( lm ) && + lmp->select_cells && + lm_select_cells_hit_test( lmp, ep, NULL, NULL, NULL ) ) + { + *ep = oevt; + return 4; + } + if ( LIST_IS_ENABLED( lm ) && + lmp->sizable_columns && + lm_size_hit_test( lm, ep, &column ) ) + { + *ep = oevt; + return 2; + } + if ( retval ) + { + if ( !is_vis ) + { + *ep = oevt; + return 5; + } + if ( CELL_IS_SELECTABLE( lm, row, column ) ) + retval = 5; + if ( row == -1 ) + retval = 5; + if ( row >= 0 && ( lmp->cell_data[row][column].icon_rid + || lmp->cell_data[row][column].bitmap != NULL ) ) + retval = 5; + if ( row >= 0 && lmp->cell_data[row][column].button_full_cell ) + retval = 5; + if ( LIST_IS_ENABLED( lm ) && + lmp->movable_columns && + lm_hit_test( lm, ep, &oevt, &row, &column, NULL, NULL, NULL ) ) + if ( row == -1 ) + retval = 3; + } + break; + } + case XinEventCharacter: + if ( xi_get_pref( XI_PREF_KEEP_FOCUS_FIXED ) + && ep->v.character.ch != XI_KEY_NEXT + && ep->v.character.ch != XI_KEY_PREV ) + { + int row, + column; + BOOLEAN v_scrolled; + LM_FOCUS_CELL_VISIBLE_FORCE_ARGS args; + + lm_focus_cell_get( lmp, &row, &column, &v_scrolled ); + MEMCLEAR( args ); + args.lmp = lmp; + args.row = row; + args.column = column; + args.vert_scrolled = v_scrolled; + lm_focus_cell_visible_force( &args ); + } + { + long button_key; + BOOLEAN shift, + control, + alt; + int focus_row, + focus_column; + BOOLEAN h_scrolled; + + button_key = xi_get_pref( XI_PREF_BUTTON_KEY ); + shift = ( BOOLEAN ) ( ( button_key & XI_MOD_SHIFT ) != 0 ); + control = ( BOOLEAN ) ( ( button_key & XI_MOD_CONTROL ) != 0 ); + alt = ( BOOLEAN ) ( ( button_key & XI_MOD_ALT ) != 0 ); + button_key &= 0xffffffL; + if ( button_key == ep->v.character.ch && + shift == ep->v.character.shift && + control == ep->v.character.control && + alt == ep->v.character.alt ) + { + if ( lm_focus_cell_get( lmp, &focus_row, &focus_column, &h_scrolled ) + && lmp->cell_data[focus_row][focus_column].button ) + do_lm_cb( ( LM ) lmp, LM_CB_CELL_BTN, focus_row, focus_column, ep, NULL, 0 ); + return FALSE; + } + } + + if ( lmp->single_select ) + { + BOOLEAN clear_buffer = TRUE; + switch ( ep->v.character.ch ) + { + case XI_KEY_UP: + { + int cur_row = find_selection( lmp ); + + if ( cur_row == -1 ) + cur_row = 0; + else + { + if ( cur_row == 0 ) + xi_scroll( lmp->list_obj, -1 ); + else + cur_row--; + } + select_row( lm, cur_row, -1, FALSE ); + break; + } + case XI_KEY_DOWN: + { + int cur_row = find_selection( lmp ); + + if ( cur_row == -1 ) + cur_row = 0; + else + { + if ( cur_row == lmp->last_fully_vis ) + xi_scroll( lmp->list_obj, 1 ); + else + cur_row++; + } + select_row( lm, cur_row, -1, FALSE ); + break; + } + case XI_KEY_PREV: + xi_scroll( lmp->list_obj, XI_SCROLL_PGUP ); + select_row( lm, lmp->last_fully_vis, -1, FALSE ); + break; + case XI_KEY_NEXT: + xi_scroll( lmp->list_obj, XI_SCROLL_PGDOWN ); + select_row( lm, 0, -1, FALSE ); + break; + case XI_KEY_HOME: + case XI_KEY_LHOME: + xi_scroll( lmp->list_obj, XI_SCROLL_FIRST ); + select_row( lm, 0, -1, FALSE ); + break; + case XI_KEY_END: + case XI_KEY_LEND: + xi_scroll( lmp->list_obj, XI_SCROLL_LAST ); + select_row( lm, lmp->last_fully_vis, -1, FALSE ); + break; + case '\r': + case ' ': + case '\n': + row = find_selection( lmp ); + select_row( lm, row, -1, TRUE ); + clear_buffer = FALSE; +#if 0 + if ( row != -1 ) + { + LM_CB_DATA lm_cb_data; + + lm_cb_data.lm = lm; + lm_cb_data.cb_type = LM_CB_SELECT; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.row = ( unsigned char ) row; + lm_cb_data.column = ( unsigned char ) get_select_column( lmp ); + lm_cb_data.v.select.selected = TRUE; + lm_cb_data.v.select.dbl_click = TRUE; + lm_cb_data.v.select.shift = FALSE; + lm_cb_data.v.select.control = FALSE; + ( *lmp->lm_cb ) ( &lm_cb_data ); + } +#endif + break; + default: + if ( lmp->position_by_typing_cid > 0 ) + { + int len, old_len; + if (lmp->position_by_typing_buf == NULL) + { + lmp->position_by_typing_buf = (char *)xi_tree_malloc( 100 * sizeof(char), lmp->list_obj ); + memset( lmp->position_by_typing_buf, '\0', 100 * sizeof( char ) ); + } + len = old_len = strlen( lmp->position_by_typing_buf ); + if (ep->v.character.ch == '\b') + { + if (len > 0) + { + lmp->position_by_typing_buf[len-1] = '\0'; + len--; + } + } else { + lmp->position_by_typing_buf[len] = (char)(toupper(ep->v.character.ch)); + lmp->position_by_typing_buf[len+1] = '\0'; + len++; + } + /* Find the row that matches the buffer and scroll to it. */ + if (len == 0) + xi_scroll( lmp->list_obj, XI_SCROLL_FIRST ); + else { + BOOLEAN use_allocate_free = FALSE; + BOOLEAN do_first = FALSE; /* Should we send an XIE_GET_FIRST the first time thru the loop? */ + BOOLEAN done_first = FALSE; /* have we been thru the loop at least once? */ + BOOLEAN do_get = TRUE; /* Should we send an XIE_GET_? at all? */ + BOOLEAN found = FALSE; + BOOLEAN right_row = FALSE; + int comp_len; + int comp_result; + long spec_rec, data_rec = 0L, swap_rec, start_rec = 0L; + XI_EVENT xiev; + char text_buffer[200]; + int col_nbr; + + { + int nbr_cols; + XI_OBJ **col; + col_nbr = 0; + col = xi_get_member_list( lmp->list_obj, & nbr_cols ); + while (nbr_cols) + { + if ((*col)->cid == lmp->position_by_typing_cid) + break; + col_nbr++; + nbr_cols--; + col++; + } + if (!nbr_cols) + return FALSE; + } + MEMCLEAR( xiev ); + /* We need two handles, which we will alternate between spec and data_rec. */ + xiev.type = XIE_REC_ALLOCATE; + xiev.v.rec_allocate.list = lmp->list_obj; + (itf->v.itf->xi_eh) ( itf, &xiev ); + if ( xiev.refused ) + return FALSE; + spec_rec = xiev.v.rec_allocate.record; + if (spec_rec != 0) + { + use_allocate_free = TRUE; + (itf->v.itf->xi_eh) ( itf, &xiev ); + if ( xiev.refused ) + return FALSE; + data_rec = xiev.v.rec_allocate.record; + } + + if (old_len > len || len == 1) + do_first = TRUE; + + while (!found) + { + MEMCLEAR( xiev ); + xiev.v.rec_request.list = lmp->list_obj; + if (use_allocate_free) + xiev.v.rec_request.data_rec = data_rec; + if (!done_first) + { + if (do_first) + xiev.type = XIE_GET_FIRST; + else { + int row = find_selection( lmp ); + if (row != -1) + { + xiev.type = XIE_GET_NEXT; + start_rec = lmp->recs[row]; + do_get = FALSE; /* We have the record. Don't send an XIE_GET_? */ + } else + xiev.type = XIE_GET_FIRST; + } + } else { + xiev.type = XIE_GET_NEXT; + xiev.v.rec_request.spec_rec = spec_rec; + } + if (do_get) + { + (itf->v.itf->xi_eh) ( itf, &xiev ); + if ( xiev.refused ) + break; + } + done_first = TRUE; + if (use_allocate_free) + { + swap_rec = data_rec; + data_rec = spec_rec; + spec_rec = swap_rec; + } else + spec_rec = xiev.v.rec_request.data_rec; + MEMCLEAR( xiev ); + xiev.type = XIE_CELL_REQUEST; + xiev.v.cell_request.list = lmp->list_obj; + xiev.v.cell_request.s = text_buffer; + xiev.v.cell_request.len = 200; + if (do_get) + xiev.v.cell_request.rec = spec_rec; + else + xiev.v.cell_request.rec = start_rec; + xiev.v.cell_request.col_nbr = col_nbr; + (itf->v.itf->xi_eh) ( itf, &xiev ); + comp_len = len; + if (xiev.v.cell_request.len < comp_len) + comp_len = xiev.v.cell_request.len; + { + int i = 0; + for (; i < comp_len; i++) + xiev.v.cell_request.s[i] = toupper( xiev.v.cell_request.s[i] ); + } + comp_result = strncmp(lmp->position_by_typing_buf, xiev.v.cell_request.s, comp_len); + if (comp_result == 0) { + found = TRUE; + right_row = TRUE; + } else if (comp_result < 0) { + found = TRUE; + right_row = FALSE; + do_get = TRUE; + } else + do_get = TRUE; + } + if (right_row) + { + int i; + long test_rec; + if (do_get) + test_rec = spec_rec; + else + test_rec = start_rec; + + for (i = 0; i < lmp->nbr_realized_rows; i++) + if (lmp->recs[i] == test_rec) + break; + if (i >= lmp->nbr_realized_rows) + { + XI_SCROLL_RECORD_ARG arg; + MEMCLEAR( arg ); + arg.xi_obj = lmp->list_obj; + if (do_get) + arg.record = spec_rec; + else + arg.record = start_rec; + arg.rec_at_top = TRUE; + xi_scroll_record( &arg ); + for (i = 0; i < lmp->nbr_realized_rows; i++) + if (lmp->recs[i] == test_rec) + break; + } + if (i < lmp->nbr_realized_rows) + { + long attrib; + attrib = lm_get_attrib( lm, LM_ROW, i, 0, FALSE ); + if ( !(attrib & LM_ROW_ATR_SELECTED) ) + select_row( lm, i, -1, FALSE ); + } + } else { + XinBeep(); + lmp->position_by_typing_buf[len-1] = '\0'; + } + if (use_allocate_free) + { + MEMCLEAR( xiev ); + xiev.type = XIE_REC_FREE; + xiev.v.rec_free.list = lmp->list_obj; + xiev.v.rec_free.record = data_rec; + (itf->v.itf->xi_eh) ( itf, &xiev ); + if (!right_row || !do_get) + { + xiev.v.rec_free.record = spec_rec; + (itf->v.itf->xi_eh) ( itf, &xiev ); + } + } + } + clear_buffer = FALSE; + } else + return FALSE; + } + if (clear_buffer && lmp->position_by_typing_buf != NULL) + lmp->position_by_typing_buf[0] = '\0'; + return TRUE; + } + + if ( !lmp->sizing_row ) + { + BOOLEAN nav_ret = FALSE; + + if ( !lmp->itf_obj->v.itf->pasting ) + nav_ret = ( BOOLEAN ) navigate_char_event( lm, ep ); + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + { + int ch = ep->v.character.ch; + retval = send_cell_event( lm, ep, FALSE, ( BOOLEAN ) ( !nav_ret ) ); + /* If the high-level application wants to do its own autotabbing, it + * will change the character to a tab, so we need to process that + * here. */ + if ( ep->v.character.ch != ch ) + nav_ret = ( BOOLEAN ) navigate_char_event( lm, ep ); + } + else + retval = FALSE; + } + break; + case XinEventDestroy: + retval = 0; + break; + case XinEventTimer: + case XinEventMenuCommand: + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + retval = send_cell_event( lm, ep, FALSE, TRUE ); + break; + default: + break; + } + if ( ep_needs_restore ) + *ep = oevt; + return ( retval ); +} diff --git a/src/xi01/xilmst.c b/src/xi01/xilmst.c new file mode 100644 index 000000000..dee2edbcb --- /dev/null +++ b/src/xi01/xilmst.c @@ -0,0 +1,915 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#include "xi.h" +#include "xitext.h" +#include "xilm.h" +#include "xilmst.h" +#include "xiutils.h" +#include "xidisply.h" +#include + +void +lm_focus_set( long lm, int row, int column, BOOLEAN v_scrolled, BOOLEAN set ) +{ + LM_DATA *lmp = ( LM_DATA * ) lm; + + if ( set ) + { + LM_FOCUS_CELL_VISIBLE_FORCE_ARGS args; + + MEMCLEAR( args ); + args.lmp = lmp; + args.row = row; + args.column = column; + args.vert_scrolled = v_scrolled; + lm_focus_cell_visible_force( &args ); + } + else + { + lm_focus_remove( lmp, row, column, v_scrolled ); + } +} + +void +lm_focus_cell_visible_force( LM_FOCUS_CELL_VISIBLE_FORCE_ARGS * args ) +{ +/* + LM_DATA *lmp; + int row; + int column; + int vert_scrolled; +*/ + LM_DATA *lmp = args->lmp; + LM_COLUMN_DATA *lmcdp; + unsigned long attrib, + cell_attrib; + int c; + XinRect mr; + int focus_row, + focus_column; + BOOLEAN v_scrolled; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + if ( focus_row == args->row && + focus_column == args->column && + v_scrolled == FALSE && + lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ) + return; + /* force a vertically scrolled row to be visible */ + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VERTICALLY_SCROLLED ) + { + LM_SCROLL_ARG lm_scroll_arg; + int row; + BOOLEAN found = FALSE; + + for ( row = 0; row < lmp->nbr_realized_rows; ++row ) + { + if ( lmp->focus_state->focus_rec == lmp->recs[row] ) + { + found = TRUE; + break; + } + } + if ( !found ) + { + MEMCLEAR( lm_scroll_arg ); + lm_scroll_arg.lm = ( LM ) lmp; + /* lm_scroll_arg.nbr_lines = 0; lm_scroll_arg.percent = 0; + * lm_scroll_arg.same_cell = 0; */ + lm_scroll_arg.rec = lmp->focus_state->focus_rec; + lm_scroll_arg.have_rec = TRUE; + lm_scroll_arg.color = lmp->focus_state->focus_rec_color; + lm_scroll_arg.attrib = lmp->focus_state->focus_rec_attrib; + lm_scroll_arg.row_height = lmp->focus_state->focus_rec_height; + lm_scroll_arg.rec_at_top = lmp->focus_state->focus_rec_is_above; + lm_scroll( &lm_scroll_arg ); + XinWindowPaintForce( lmp->win ); + } + } + + mr = lmp->mlr; + if ( lmp->pixel_width ) + mr.right = mr.left + lmp->pixel_width + BORDER_WIDTH; + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + lmcdp = lmp->lm_column_data[focus_column]; + attrib = lmcdp->attrib; + + cell_attrib = lm_get_attrib( ( LM ) lmp, LM_CELL, focus_row, focus_column, + v_scrolled ) & ( XI_ATR_HCENTER | XI_ATR_RJUST ); + if ( cell_attrib ) + { + attrib &= ~( XI_ATR_HCENTER | XI_ATR_RJUST ); + attrib |= cell_attrib; + } + + /* force cell to be visible */ + c = min( focus_column, lmp->nbr_columns - 1 ); + if ( c >= lmp->fixed_columns && c < lmp->first_vis ) + lm_local_hscroll( ( LM ) lmp, c - lmp->first_vis ); + else + { + if ( c > lmp->last_vis ) + { + int first_col; + + c++; + c = min( c, lmp->nbr_columns ); + first_col = lm_get_left_most_far_right_col( lmp, c ); + lm_local_hscroll( ( LM ) lmp, first_col - lmp->first_vis ); + } + } +#if 0 + /* this should never get executed */ + if ( focus_row < lmp->first_fully_vis ) + { + int delta, + idx2, + pix2, + old_pix; + XinRect tmp_rct; + + make_room_rows( lmp, focus_row - lmp->first_fully_vis, FALSE ); + idx2 = focus_row; + pix2 = lmp->pix_offsets[idx2]; + old_pix = -lmp->rrr_offset; + delta = old_pix - pix2; + lmp->rrr_offset += delta; + calculate_pix_offsets( lmp, FALSE ); + if ( !lmp->itf_obj->v.itf->half_baked ) + XinWindowPaintForce( lmp->win ); + xi_set_update_obj( lmp->list_obj ); + lm_get_scroll_rct( lmp, &tmp_rct ); + xi_scroll_rect( lmp->win, &tmp_rct, 0, delta ); + do_scroll_bar( lmp->list_obj->v.list ); + } +#endif + if ( focus_row > lmp->last_fully_vis ) + { + int pix, + delta; + XinRect tmp_rct; + + delta = 0; + while ( TRUE ) + { + if ( focus_row <= lmp->last_fully_vis ) + break; + pix = lmp->pix_heights[0]; + delta += pix; + lm_make_rrr_room_pix( lmp, pix, FALSE ); + lmp->rrr_offset -= pix; + calculate_pix_offsets( lmp, FALSE ); + calculate_visibles( lmp ); + } + if ( !lmp->itf_obj->v.itf->half_baked ) + XinWindowPaintForce( lmp->win ); + xi_set_update_obj( lmp->list_obj ); + lm_get_scroll_rct( lmp, &tmp_rct ); + xi_scroll_rect( lmp->win, &tmp_rct, 0, -delta ); + do_scroll_bar( lmp->list_obj->v.list ); + + if ( !lmp->get_all_records ) + { + int nbr_to_free, + cnt, + i, + idx; + + nbr_to_free = lmp->first_fully_vis; + if ( nbr_to_free > 0 ) + { + for ( cnt = 0; cnt < nbr_to_free; cnt++ ) + { + lmp->rrr_offset += lmp->pix_heights[cnt]; + lm_do_rec_event( lmp, cnt, XIE_REC_FREE ); + } + + for ( idx = nbr_to_free; idx < lmp->nbr_realized_rows; ++idx ) + lm_row_copy( lmp, idx, idx - nbr_to_free ); + lm_adjust_rows( lmp, -nbr_to_free ); + + lmp->nbr_realized_rows -= cnt; + } + + /* free any unnecessary records at the end of the list */ + nbr_to_free = lmp->nbr_realized_rows - ( lmp->last_fully_vis + 2 ); + if ( nbr_to_free > 0 ) + { + for ( i = lmp->nbr_realized_rows - nbr_to_free, cnt = 0; cnt < nbr_to_free; + i++, cnt++ ) + lm_do_rec_event( lmp, i, XIE_REC_FREE ); + lmp->nbr_realized_rows -= cnt; + } + + calculate_pix_offsets( lmp, TRUE ); + } + } + if ( lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE ) + lm_focus_cell_visible_attempt( lmp ); +} + +void +lm_focus_cell_text_set( LM_DATA * lmp, BOOLEAN preserve_focus_text, const char *s, + int row, int col, BOOLEAN v_scrolled ) +{ + int focus_row, + focus_column; + BOOLEAN focus_v_scrolled; + + if ( lm_focus_list_has( lmp ) ) + { + lm_focus_cell_get( lmp, &focus_row, &focus_column, &focus_v_scrolled ); + if ( lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE && + row == focus_row && + col == focus_column && + v_scrolled == focus_v_scrolled && + preserve_focus_text != TRUE ) + { + int len; + LM_COLUMN_DATA *lm_column_data; + int pix_spacing; + LM_CELL_DATA *cell_data; + + len = strlen( s ) + 1; + if ( lmp->focus_state->focus_cell_text ) + lmp->focus_state->focus_cell_text = ( char * ) xi_tree_realloc( lmp->focus_state->focus_cell_text, len ); + else + lmp->focus_state->focus_cell_text = ( char * ) xi_tree_malloc( len, lmp ); + strcpy( lmp->focus_state->focus_cell_text, s ); + lm_column_data = lmp->lm_column_data[focus_column]; + cell_data = &lmp->cell_data[focus_row][focus_column]; + pix_spacing = lm_column_data->pix_width - + ( cell_data->button ? lmp->pix_row_spacing : 0 ); + xi_text_pix_width_and_text_set( cell_data->xi_text, lmp->focus_state->focus_cell_text, + pix_spacing, TRUE ); + if ( lmp->lm_column_data[col]->attrib | XI_ATR_AUTOSELECT ) + { + lmp->focus_state->focus_cell_ip1 = 0; + lmp->focus_state->focus_cell_ip2 = strlen( s ); + } + else + { + lmp->focus_state->focus_cell_ip1 = 0; + lmp->focus_state->focus_cell_ip2 = 0; + } + lmp->focus_state->button = cell_data->button; + lmp->focus_state->button_full_cell = cell_data->button_full_cell; + } + } +} + +long +lm_focus_rec_get( LM_DATA * lmp ) +{ + return lmp->focus_state->focus_rec; +} + +BOOLEAN +lm_focus_cell_has( LM_DATA * lmp, int row, int column, BOOLEAN v_scrolled ) +{ + XI_ITF_DATA *itf; + XI_OBJ *focus_obj; + XI_CELL_DATA *cd; + + if ( lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE ) + return FALSE; + itf = lmp->itf_obj->v.itf; + focus_obj = itf->focus_obj; + if ( focus_obj != NULL && focus_obj->parent == lmp->list_obj && + focus_obj->type == XIT_CELL ) + { + cd = &focus_obj->v.cell; + return ( cd->row == row && cd->column == column + && cd->is_vert_scrolled == v_scrolled ); + } + return FALSE; +} + +void +lm_focus_rec_color_set( LM_DATA * lmp, XinColor color ) +{ + lmp->focus_state->focus_rec_color = color; +} + +void +lm_focus_cell_attrib_set( LM_DATA * lmp, unsigned long attrib ) +{ + lmp->focus_state->focus_cell_attrib = attrib; +} + +void +lm_focus_selection_get( LM_DATA * lmp, int *c1, int *c2 ) +{ + if ( lm_focus_list_has( lmp ) ) + { + XI_TEXT *text; + + text = xi_text_focus_get( lmp->win ); + if ( text ) + xi_text_selection_get( text, c1, c2 ); + } + else + *c1 = *c2 = 0; +} + +char * +lm_focus_cell_text_get( LM_DATA * lmp ) +{ + return lmp->focus_state->focus_cell_text; +} + +LM_FOCUS +lm_focus_state_get( LM_DATA * lmp ) +{ + return lmp->focus_state->where; +} + +/*------------------------------------------------------------------------- +function: lm_stop_edit +lm: current lm +-------------------------------------------------------------------------*/ +static void +lm_stop_edit( LM lm, BOOLEAN do_update, int row, int column, LM_FOCUS state_was ) +{ + LM_DATA *lmp = LMP( lm ); + XI_TEXT *text; + LM_CELL_DATA *cell_data; + + cell_data = &lmp->cell_data[row][column]; + text = cell_data->xi_text; + if ( text && !cell_data->button_full_cell ) + { + xi_text_editing_stop( text ); + XinWindowPaintForce( lmp->win ); + } + /* if lmp->row_focus_border is TRUE, don't redraw, because old focus row will + * be invalidated */ + if ( ( do_update && state_was == LM_FOCUS_VISIBLE ) || + (do_update && cell_data->button_full_cell)) + redraw_cell( lm, row, column, FALSE ); +} + +/* ------------------------------------------------------------------- */ +/* lm_focus_cell_is_visible */ +/* ------------------------------------------------------------------- */ +/* +TODO it is possible here that focus has been moved such that it is now +visible, but the state still indicates that it is not. +*/ +BOOLEAN +lm_focus_cell_is_visible( LM_DATA * lmp, BOOLEAN * is_hscrolled ) +{ + if ( is_hscrolled ) + *is_hscrolled = FALSE; + if ( lm_focus_state_get( lmp ) == LM_FOCUS_HORIZONTALLY_SCROLLED ) + { + *is_hscrolled = TRUE; + return FALSE; + } + return ( lm_focus_state_get( lmp ) == LM_FOCUS_VISIBLE ); +} + +/* +Semantics: this function attempts to make the focus be visible. +It then sets the state as appropriate. If it succeeded, then +it sets state to LM_FOCUS_VISIBLE. If it failed, then it sets +focus to LM_FOCUS_VERTICALLY_SCROLLED or LM_FOCUS_HORIZONTALLY_SCROLLED. +*/ +void +lm_focus_cell_visible_attempt( LM_DATA * lmp ) +{ + int focus_row, + focus_column; + BOOLEAN v_scrolled; + + if ( !lm_focus_list_has( lmp ) ) + return; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + if ( focus_column < lmp->fixed_columns || + ( focus_column >= lmp->first_vis && + focus_column <= lmp->last_vis ) ) + { + LM_COLUMN_DATA *lm_column_data; + XinRect cell_r; + unsigned long attrib, + cell_attrib; + LM_CELL_DATA *cell_data; + XinRect mr; + BOOLEAN text_was_invisible; + LM_FOCUS focus; + int leading, + ascent, + descent; + int col_offset; + + col_offset = ( int ) xi_get_pref( XI_PREF_COLUMN_OFFSET ); + + if ( lm_focus_state_get( lmp ) == LM_FOCUS_VERTICALLY_SCROLLED || + lm_focus_state_get( lmp ) == LM_FOCUS_TEMP_INVISIBLE ) + { + int cnt; + + for ( cnt = 0; cnt < lmp->nbr_realized_rows; ++cnt ) + { + if ( lmp->recs[cnt] == lmp->focus_state->focus_rec ) + { + if ( cnt <= lmp->last_fully_vis ) + { + lm_focus_cell_set( lmp, cnt, focus_column, FALSE ); + focus_row = cnt; + } + break; + } + } + if ( cnt > lmp->last_fully_vis ) + { + lmp->focus_state->where = LM_FOCUS_VERTICALLY_SCROLLED; + return; + } + } + focus = lm_focus_state_get( lmp ); + text_was_invisible = FALSE; + if ( focus == LM_FOCUS_HORIZONTALLY_SCROLLED || + focus == LM_FOCUS_VERTICALLY_SCROLLED || + focus == LM_FOCUS_TEMP_INVISIBLE ) + text_was_invisible = TRUE; + mr = lmp->mlr; + if ( lmp->pixel_width ) + mr.right = mr.left + lmp->pixel_width; + lm_column_data = lmp->lm_column_data[focus_column]; + attrib = lm_column_data->attrib; + cell_data = &lmp->cell_data[focus_row][focus_column]; + if ( cell_data->xi_text != NULL ) + xi_text_clip_set( cell_data->xi_text, &mr ); + if ( text_was_invisible ) + { + cell_data->attrib = lmp->focus_state->focus_cell_attrib; + if ( cell_data->font ) + XinFontDestroy( cell_data->font ); + if ( lmp->focus_state->focus_cell_font ) + { + XinFontCopy( &cell_data->font, lmp->focus_state->focus_cell_font ); + if ( cell_data->xi_text != NULL ) + xi_text_font_set( cell_data->xi_text, cell_data->font ); + } else + cell_data->font = NULL; + cell_data->color = lmp->focus_state->focus_cell_color; + cell_data->back_color = lmp->focus_state->focus_cell_back_color; + cell_data->button = lmp->focus_state->button; + cell_data->button_full_cell = lmp->focus_state->button_full_cell; + cell_data->button_on_left = lmp->focus_state->button_on_left; + cell_data->button_icon_rid = lmp->focus_state->button_icon_rid; + cell_data->button_bitmap = lmp->focus_state->button_bitmap; + } + cell_attrib = cell_data->attrib & ( XI_ATR_HCENTER | XI_ATR_RJUST ); + if ( cell_attrib ) + { + attrib &= ~( XI_ATR_HCENTER | XI_ATR_RJUST ); + attrib |= cell_attrib; + } + /* Create the focus cell */ + + if ( cell_data->button_full_cell ) + { + lmp->cur_font = lmp->font; + lmp->old_row_height = lmp->pix_heights[focus_row]; + lmp->focus_state->focus_rec = 0L; + lmp->focus_state->where = LM_FOCUS_VISIBLE; + redraw_cell( ( LM ) lmp, focus_row, focus_column, FALSE ); + } + else + { + lmp->cur_font = lmp->font; + XinFontMetricsGet( lmp->cur_font, &leading, &ascent, &descent ); + lm_xi_text_prect_get( lmp, lm_column_data, cell_data, focus_row, focus_column, + col_offset, leading, ascent, descent, &cell_r ); + if ( !lm_column_data->wrap_text ) + xi_text_pix_width_set( cell_data->xi_text, lm_column_data->pix_width - + ( cell_data->button ? lmp->pix_row_spacing : 0 ) ); + xi_text_prect_set( cell_data->xi_text, &cell_r ); + xi_text_color_fore_set( cell_data->xi_text, lmp->active_color ); + xi_text_color_back_set( cell_data->xi_text, lmp->active_back_color ); + if ( cell_data->back_color ) + xi_text_color_back_set( cell_data->xi_text, cell_data->back_color ); + if ( text_was_invisible ) + { + xi_text_set( cell_data->xi_text, lmp->focus_state->focus_cell_text ); + } + cell_data->valid_data = TRUE; + lmp->old_row_height = lmp->pix_heights[focus_row]; + lmp->focus_state->focus_rec = 0L; + if ( text_was_invisible ) + { + LM_COLUMN_DATA *lm_column_data; + int pix_spacing; + + lm_column_data = lmp->lm_column_data[focus_column]; + pix_spacing = lm_column_data->pix_width - + ( cell_data->button ? lmp->pix_row_spacing : 0 ); + xi_text_pix_width_and_text_set( cell_data->xi_text, lmp->focus_state->focus_cell_text, + pix_spacing, TRUE ); + xi_text_selection_set_internal( cell_data->xi_text, + lmp->focus_state->focus_cell_ip1, + lmp->focus_state->focus_cell_ip2, + lmp->focus_state->focus_cell_start_ip, TRUE, TRUE ); + } + else + { + if ( lmp->have_mouse ) + { + if ( ( lm_column_data->attrib & ( LM_COL_ATR_AUTOSELECT | LM_COL_ATR_READONLY ) ) == + ( LM_COL_ATR_AUTOSELECT | LM_COL_ATR_READONLY ) ) + xi_text_selection_set( cell_data->xi_text, 0, SHRT_MAX ); + else if ( ( lm_column_data->attrib & LM_COL_ATR_AUTOSELECT ) && xi_get_pref( XI_PREF_AUTOSEL_ON_MOUSE ) ) + xi_text_selection_set( cell_data->xi_text, 0, SHRT_MAX ); + else + xi_text_selection_set( cell_data->xi_text, 0, 0 ); + } + else + { + if ( lm_column_data->attrib & LM_COL_ATR_AUTOSELECT ) + xi_text_selection_set( cell_data->xi_text, 0, SHRT_MAX ); + else + xi_text_selection_set( cell_data->xi_text, 0, 0 ); + } + } + xi_text_editing_start( cell_data->xi_text ); + } + lmp->focus_state->where = LM_FOCUS_VISIBLE; + redraw_cell( ( LM ) lmp, focus_row, focus_column, FALSE ); + } + else + { + if ( lm_focus_state_get( lmp ) != LM_FOCUS_VERTICALLY_SCROLLED ) + { + lmp->focus_state->where = LM_FOCUS_HORIZONTALLY_SCROLLED; + if ( lmp->focus_state->focus_rec ) + { + int cnt; + + /* the following loop should *always* find a row, because the only + * reason the cell is not visible is because the list is horizontally + * scrolled. */ + for ( cnt = 0; cnt < lmp->nbr_realized_rows; ++cnt ) + { + if ( lmp->recs[cnt] == lmp->focus_state->focus_rec ) + { + lm_focus_cell_set( lmp, cnt, focus_column, FALSE ); + break; + } + } + if ( cnt == lmp->nbr_realized_rows ) + lmp->focus_state->where = LM_FOCUS_VERTICALLY_SCROLLED; + } + } + } +} + +unsigned long +lm_focus_rec_attrib_get( LM_DATA * lmp ) +{ + return lmp->focus_state->focus_rec_attrib; +} + +unsigned long +lm_focus_cell_attrib_get( LM_DATA * lmp ) +{ + return lmp->focus_state->focus_cell_attrib; +} + +void +lm_focus_cell_invis_make( LM_DATA * lmp ) +{ + XI_TEXT *text; + + if ( !lm_focus_list_has( lmp ) ) + return; + if ( lm_focus_state_get( lmp ) != LM_FOCUS_VISIBLE ) + return; + text = xi_text_focus_get( lmp->win ); + if ( text && xi_text_editing_is( text ) ) + { + int focus_row, + focus_column; + int ip1, + ip2, + start_ip; + BOOLEAN v_scrolled; + LM_CELL_DATA *cell_data; + XI_TEXT *text; + + lmp->focus_state->where = LM_FOCUS_TEMP_INVISIBLE; + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + lmp->focus_state->focus_rec = lmp->recs[focus_row]; + lmp->focus_state->focus_rec_color = lmp->row_colors[focus_row]; + lmp->focus_state->focus_rec_attrib = lmp->row_attribs[focus_row]; + lmp->focus_state->focus_rec_height = lmp->pix_heights[focus_row]; + + cell_data = &lmp->cell_data[focus_row][focus_column]; + if ( lmp->focus_state->focus_cell_font ) + { + XinFontDestroy( lmp->focus_state->focus_cell_font ); + lmp->focus_state->focus_cell_font = NULL; + } + if ( cell_data->font ) + XinFontCopy( &lmp->focus_state->focus_cell_font, cell_data->font ); + lmp->focus_state->focus_cell_color = cell_data->color; + lmp->focus_state->focus_cell_back_color = cell_data->back_color; + lmp->focus_state->focus_cell_attrib = cell_data->attrib; + xi_text_selection_get_internal( cell_data->xi_text, &ip1, &ip2, &start_ip ); + lm_focus_cell_text_set( lmp, FALSE, xi_text_get( cell_data->xi_text ), focus_row, + focus_column, FALSE ); + lmp->focus_state->focus_cell_ip1 = ip1; + lmp->focus_state->focus_cell_ip2 = ip2; + lmp->focus_state->focus_cell_start_ip = start_ip; + lmp->focus_state->button = cell_data->button; + lmp->focus_state->button_full_cell = cell_data->button_full_cell; + lmp->focus_state->button_on_left = cell_data->button_on_left; + lmp->focus_state->button_icon_rid = cell_data->button_icon_rid; + lmp->focus_state->button_bitmap = cell_data->button_bitmap; + if ( lmp->focus_state->focus_cell_ip1 != lmp->focus_state->focus_cell_ip2 ) + redraw_cell( ( LM ) lmp, focus_row, focus_column, FALSE ); + text = xi_text_focus_get( lmp->win ); + xi_text_editing_stop( text ); + } +} + +BOOLEAN +lm_focus_list_has( LM_DATA * lmp ) +{ + XI_ITF_DATA *itf; + BOOLEAN retval; + + itf = lmp->itf_obj->v.itf; + retval = ( itf->focus_obj != NULL && itf->focus_obj->parent == lmp->list_obj ); + return retval; +} + +BOOLEAN +lm_focus_cell_get( LM_DATA * lmp, int *rowp, int *columnp, BOOLEAN * is_vert_scrolled ) +{ + XI_ITF_DATA *itf; + XI_OBJ *focus_obj; + XI_CELL_DATA *cd; + + itf = lmp->itf_obj->v.itf; + focus_obj = itf->focus_obj; + if ( focus_obj != NULL && focus_obj->parent == lmp->list_obj && + focus_obj->type == XIT_CELL ) + { + cd = &focus_obj->v.cell; + *rowp = cd->row; + *columnp = cd->column; + *is_vert_scrolled = cd->is_vert_scrolled; + return TRUE; + } + *rowp = 0; + *columnp = 0; + *is_vert_scrolled = FALSE; + return FALSE; +} + +void +lm_focus_cell_set( LM_DATA * lmp, int row, int column, BOOLEAN is_vert_scrolled ) +{ + XI_ITF_DATA *itf; + XI_OBJ *focus_obj; + XI_CELL_DATA *cd; + + itf = lmp->itf_obj->v.itf; + focus_obj = itf->focus_obj; + if ( focus_obj != NULL && focus_obj->parent == lmp->list_obj && + focus_obj->type == XIT_CELL ) + { + cd = &focus_obj->v.cell; + cd->row = row; + cd->column = column; + cd->is_vert_scrolled = ( unsigned char ) is_vert_scrolled; + return; + } + XinError( 20921, XinSeverityFatal, 0L ); + return; +} + +#if 0 +/*------------------------------------------------------------------------- +function: lm_start_edit +lm: current lm +row: relevant row +column: relevant column +notes: create a text core edit field in the position of the + cell of interest, and copy in the necessary attributes + and text from the list +-------------------------------------------------------------------------*/ +static void +lm_start_edit( LM lm, int row, int column ) +{ + LM_DATA *lmp = LMP( lm ); + int focus_row, + focus_column; + BOOLEAN v_scrolled; + LM_FOCUS_CELL_VISIBLE_FORCE_ARGS args; + + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + if ( !( focus_row == row && focus_column == column ) ) + XinError( 30209, XinSeverityFatal, 0L ); + + MEMCLEAR( args ); + args.lmp = lmp; + args.row = row; + args.column = column; + args.vert_scrolled = v_scrolled; + lm_focus_cell_visible_force( &args ); +} + +#endif + +void +lm_focus_create_temp_row( LM_DATA * lmp ) +{ + int idx, + focus_row, + focus_column, i; + BOOLEAN v_scrolled; + LM_CELL_DATA *cell_data; + + lm_allocate_rec_info( lmp, lmp->realized_rows_array_len + 1 ); + ++lmp->nbr_realized_rows; + idx = lmp->nbr_realized_rows - 1; + lmp->recs[idx] = lm_focus_rec_get( lmp ); + /* cell_data_construct */ + cell_data = lmp->cell_data[idx]; + for ( i = 0; i < lmp->nbr_columns; ++i, ++cell_data ) + { + memset( ( char * ) cell_data, '\0', sizeof( LM_CELL_DATA ) ); + lm_xi_text_construct( lmp, idx, i ); + } + lmp->focus_state->saved_focus_rec = lm_focus_rec_get( lmp ); + + lmp->focus_state->focus_rec = 0L; + lm_focus_cell_get( lmp, &focus_row, &focus_column, &v_scrolled ); + focus_row = idx; + lm_focus_cell_set( lmp, focus_row, focus_column, TRUE ); + lm_invalidate_rows_internal( ( LM ) lmp, focus_row, focus_row, FALSE, + focus_column, TRUE ); + calculate_pix_offsets( lmp, FALSE ); + calculate_visibles( lmp ); +} + +void +lm_focus_rec_free( LM_DATA * lmp ) +{ + LM_CB_DATA lm_cb_data; + + lm_cb_data.lm = ( LM ) lmp; + lm_cb_data.cb_type = LM_CB_REC_FREE; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.v.rec_free.record = lmp->focus_state->saved_focus_rec; + ( *lmp->lm_cb ) ( &lm_cb_data ); + lm_allocate_rec_info( lmp, lmp->nbr_realized_rows - 1 ); + --lmp->nbr_realized_rows; + lmp->focus_state->focus_rec = 0L; +} + +void +lm_focus_remove( LM_DATA * lmp, int row, int column, BOOLEAN v_scrolled ) +{ + int idx; + BOOLEAN found = FALSE; + LM_FOCUS where_focus_was; + + where_focus_was = lmp->focus_state->where; + lmp->focus_state->where = LM_FOCUS_NOWHERE; + if ( where_focus_was != LM_FOCUS_NOWHERE && + where_focus_was != LM_FOCUS_TEMP_INVISIBLE && + !v_scrolled ) + lm_stop_edit( ( LM ) lmp, TRUE, row, column, where_focus_was ); + if ( lmp->focus_state->focus_rec ) + { + for ( idx = 0; idx < lmp->nbr_realized_rows; ++idx ) + { + if ( lmp->recs[idx] == lmp->focus_state->focus_rec ) + { + found = TRUE; + break; + } + } + if ( found ) + { + lmp->focus_state->focus_rec = 0L; + } + else + { + LM_CB_DATA lm_cb_data; + + lm_cb_data.lm = ( LM ) lmp; + lm_cb_data.cb_type = LM_CB_REC_FREE; + lm_cb_data.cid = lmp->cid; + lm_cb_data.win = lmp->win; + lm_cb_data.v.rec_free.record = lmp->focus_state->focus_rec; + ( *lmp->lm_cb ) ( &lm_cb_data ); + lmp->focus_state->focus_rec = 0L; + } + } +} + +void +lm_focus_cell_selection_get( LM_DATA * lmp, int *c1, int *c2 ) +{ + LM_FOCUS state; + + state = lm_focus_state_get( lmp ); + if ( state == LM_FOCUS_VISIBLE ) + { + XI_TEXT *text; + + text = xi_text_focus_get( lmp->win ); + if ( text && xi_text_editing_is( text ) ) + xi_text_selection_get( text, c1, c2 ); + else + { + *c1 = 0; + *c2 = 0; + } + } + else + { + if ( state == LM_FOCUS_HORIZONTALLY_SCROLLED || + state == LM_FOCUS_VERTICALLY_SCROLLED ) + { + *c1 = lmp->focus_state->focus_cell_ip1; + *c2 = lmp->focus_state->focus_cell_ip2; + } + else + { + *c1 = 0; + *c2 = 0; + } + } +} + +void +lm_focus_cell_selection_set( LM_DATA * lmp, int c1, int c2 ) +{ + LM_FOCUS state; + + state = lm_focus_state_get( lmp ); + if ( state == LM_FOCUS_VISIBLE ) + { + XI_TEXT *text; + + text = xi_text_focus_get( lmp->win ); + if ( text ) + xi_text_selection_set( text, c1, c2 ); + } + else + { + if ( state == LM_FOCUS_HORIZONTALLY_SCROLLED || + state == LM_FOCUS_VERTICALLY_SCROLLED ) + { + lmp->focus_state->focus_cell_ip1 = c1; + lmp->focus_state->focus_cell_ip2 = c2; + } + } +} + +void +lm_focus_rec_is_above_set( LM_DATA * lmp, BOOLEAN is_above ) +{ + lmp->focus_state->focus_rec_is_above = is_above; +} + +BOOLEAN +lm_focus_rec_is_above_get( LM_DATA * lmp ) +{ + return lmp->focus_state->focus_rec_is_above; +} + +void +lm_focus_rec_set( LM_DATA * lmp, long focus_rec ) +{ + lmp->focus_state->focus_rec = focus_rec; +} + +long +lm_focus_rec_saved_get( LM_DATA * lmp ) +{ + return lmp->focus_state->saved_focus_rec; +} + +BOOLEAN +lm_focus_cell_is_button_full_cell( LM_DATA * lmp ) +{ + return lmp->focus_state->button_full_cell; +} diff --git a/src/xi01/xilmst.h b/src/xi01/xilmst.h new file mode 100644 index 000000000..cd15eee99 --- /dev/null +++ b/src/xi01/xilmst.h @@ -0,0 +1,96 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +typedef enum +{ + LM_FOCUS_NOWHERE, + LM_FOCUS_VISIBLE, + LM_FOCUS_HORIZONTALLY_SCROLLED, + LM_FOCUS_VERTICALLY_SCROLLED, + LM_FOCUS_TEMP_INVISIBLE +} LM_FOCUS; + +typedef struct _lm_focus_state +{ + LM_FOCUS where; + long focus_rec; + long saved_focus_rec; + BOOLEAN focus_rec_is_above; + XinColor focus_rec_color; + unsigned long focus_rec_attrib; + unsigned long focus_cell_attrib; + XinFont *focus_cell_font; + XinColor focus_cell_color; + XinColor focus_cell_back_color; + int focus_rec_height; + char *focus_cell_text; + int focus_cell_ip1; + int focus_cell_ip2; + int focus_cell_start_ip; + BOOLEAN button; + BOOLEAN button_full_cell; + BOOLEAN button_on_left; + BOOLEAN button_on_focus; + int button_icon_rid; + XI_BITMAP* button_bitmap; +} LM_FOCUS_STATE; + +typedef struct +{ + LM_DATA *lmp; + LM_FOCUS focus; + int row; + int column; + int vert_scrolled; +} LM_FOCUS_STATE_SET_ARGS; + +typedef struct +{ + LM_DATA *lmp; + int row; + int column; + int vert_scrolled; +} LM_FOCUS_CELL_VISIBLE_FORCE_ARGS; + +unsigned long lm_focus_cell_attrib_get( LM_DATA * lmp ); +void lm_focus_cell_attrib_set( LM_DATA * lmp, unsigned long attrib ); +BOOLEAN lm_focus_cell_get( LM_DATA * lmp, int *row, int *col, BOOLEAN * v_scrolled ); +BOOLEAN lm_focus_cell_is_visible( LM_DATA * lmp, BOOLEAN * is_hscrolled ); +void lm_focus_cell_set( LM_DATA * lmp, int row, int col, BOOLEAN v_scrolled ); +BOOLEAN lm_focus_cell_has( LM_DATA * lmp, int row, int col, BOOLEAN v_scrolled ); +void lm_focus_cell_selection_get( LM_DATA * lmp, int *c1, int *c2 ); +void lm_focus_cell_selection_set( LM_DATA * lmp, int c1, int c2 ); +char *lm_focus_cell_text_get( LM_DATA * lmp ); +void +lm_focus_cell_text_set( LM_DATA * lmp, BOOLEAN preserve_focus_text, + const char *text, int row, int col, BOOLEAN v_scrolled ); + +BOOLEAN lm_focus_list_has( LM_DATA * lmp ); + +unsigned long lm_focus_rec_attrib_get( LM_DATA * lmp ); +void lm_focus_rec_color_set( LM_DATA * lmp, XinColor color ); +long lm_focus_rec_get( LM_DATA * lmp ); +void lm_focus_rec_set( LM_DATA * lmp, long focus_rec ); +void lm_focus_rec_is_above_set( LM_DATA * lmp, BOOLEAN is_above ); +BOOLEAN lm_focus_rec_is_above_get( LM_DATA * lmp ); +void lm_focus_rec_free( LM_DATA * lmp ); +long lm_focus_rec_saved_get( LM_DATA * lmp ); + +LM_FOCUS lm_focus_state_get( LM_DATA * lmp ); + +/* State changing functions */ +void lm_focus_cell_visible_attempt( LM_DATA * lmp ); +void lm_focus_cell_visible_force( LM_FOCUS_CELL_VISIBLE_FORCE_ARGS * args ); +void lm_focus_cell_invis_make( LM_DATA * lmp ); +void lm_focus_remove( LM_DATA * lmp, int row, int column, BOOLEAN v_scrolled ); +void lm_focus_create_temp_row( LM_DATA * lmp ); +void lm_focus_set( long lm, int row, int column, BOOLEAN v_scrolled, + BOOLEAN set ); +BOOLEAN lm_focus_cell_is_button_full_cell( LM_DATA * lmp ); diff --git a/src/xi01/xiport.c b/src/xi01/xiport.c new file mode 100644 index 000000000..7c3ca87ab --- /dev/null +++ b/src/xi01/xiport.c @@ -0,0 +1,5911 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XIN_INTERNAL_WINDOW +#define XIN_INTERNAL_FONT +#define XIN_INTERNAL_BITMAP +#define XIN_INTERNAL_PRINT_RECORD + +#define XVT_INCL_NATIVE +#define UNDEF_TASK +#include "xvt.h" +#undef UNDEF_TASK +#include "xi.h" +#include "xiport2.h" +#include "stdarg.h" + +#if XIWS == XIWS_WIN +#include +#include +#endif + +#if XIWS == XIWS_PM +#include +#endif + +#if XIWS == XIWS_WM || XIWS == XIWS_XM || XIWS == XIWS_WXGTK +#define COALESCE_UPDATES +#endif + +#define XIN_CARET_WIDTH 1 + +#define MEMCLEAR( x ) memset(( char* )&( x ), '\0', ( size_t )sizeof( x )) + +/* We are forced to cast for XVT windows */ +struct s_XinWindow +{ + int dummy; +}; + +struct s_XinFont +{ + /* Set in the XVT font convert, checked in compare since other values won't + * be set, just the xvt_fntid */ + BOOLEAN from_xvt_font; + BOOLEAN bold; + BOOLEAN italic; + XinFontFamily family; + int size; + XVT_FNTID xvt_fntid; +}; + +struct s_XinBitmap +{ + XVT_IMAGE image; +}; + +/* We are forced to cast for XVT print record */ +struct s_XinPrintRecord +{ + int dummy; +}; + +#ifdef COALESCE_UPDATES +typedef struct +{ + int coalescing; + BOOLEAN invalidated; + XinRect inv_rct; +} XinCoalesceData; + +#endif + + +typedef struct s_window_info +{ + WINDOW win; + XinWindowEventHandler event_handler; + XinWindow prev_modal; +#ifdef COALESCE_UPDATES + XinCoalesceData coalesce; +#endif +} WindowInfo; + +static WindowInfo *window_list; +static int nbr_windows; +static EVENT *cur_xvt_event; + +static XinWindow xin_modal_win; +static XinWindow xin_autoclose_win; +static BOOLEAN app_terminating; +static XinMenu *xin_finish_create_menu = NULL; +static XinWindowDef *xin_finish_create_def = NULL; +XVT_PALETTE xin_palette = NULL; + +XinWindowEventHandler xin_teh; +char *xin_buffer = NULL; +BOOLEAN xin_xvt_initialized = FALSE; + +void XinWindowCreateFinish( XinWindow win ); + +static void +realloc_array( void **ptr, int nbr, size_t sz ) +{ + BOOLEAN is_zero = ( nbr * sz ) == 0; + + if ( !*ptr ) + { + if ( is_zero ) + *ptr = NULL; + else + *ptr = ( void * ) XinMemoryAlloc( nbr * sz ); + } + else + { + if ( is_zero ) + { + XinMemoryFree( *ptr ); + *ptr = NULL; + } + else + *ptr = ( void * ) XinMemoryRealloc( *ptr, nbr * sz ); + } +} + +void +XinXvtWindowRegister( XinWindow win, XinWindowEventHandler EventHandler ) +{ + WindowInfo *info; + + ++nbr_windows; + realloc_array( ( void ** ) &window_list, nbr_windows, sizeof( WindowInfo ) ); + info = window_list + ( nbr_windows - 1 ); + info->win = ( WINDOW ) win; + info->event_handler = EventHandler; + info->prev_modal = XI_NULL_WINDOW; +#ifdef COALESCE_UPDATES + info->coalesce.coalescing = 0; +#endif +} + +static WindowInfo * +find_window_info( WINDOW win ) +{ + int cnt; + WindowInfo *info = window_list; + + for ( cnt = 0; cnt < nbr_windows && info->win != win; cnt++, info++ ) + ; + if ( cnt == nbr_windows ) + return NULL; + return info; +} + +#if XIWS == XIWS_WIN || XIWS == XIWS_PM +static WindowInfo * +find_window_info_from_HWND( HWND win ) +{ + int cnt; + WindowInfo *info = window_list; + + for ( cnt = 0; cnt < nbr_windows + && ( HWND ) xvt_vobj_get_attr( info->win, ATTR_NATIVE_WINDOW ) != win; + cnt++, info++ ) + ; + if ( cnt == nbr_windows ) + return NULL; + return info; +} + +#endif + +static void +deregister_window( WINDOW win ) +{ + WindowInfo *info; + + info = find_window_info( win ); + if ( info != NULL ) + { + int cnt = ( int ) ( info - window_list ); + + --nbr_windows; + if ( nbr_windows > cnt ) + memmove( window_list + cnt, window_list + cnt + 1, + ( nbr_windows - cnt ) * sizeof( WindowInfo ) ); + } +} + +#if XIWS == XIWS_WM +static void +xi_fix_color( COLOR * color ) +{ + if ( *color == XI_COLOR_BLACK ) + *color = XI_COLOR_WHITE; + else if ( *color == XI_COLOR_WHITE ) + *color = XI_COLOR_BLACK; +} + +#endif + +#if XIWS == XIWS_PM +/* This function is required to fix a scrolling problem on PM. */ +/**** RGM: This is a mess - there is only one "old_pm_proc" for all windows */ +PFNWP old_pm_proc = NULL; + +static MRESULT EXPENTRY +pm_proc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) +{ + switch ( msg ) + { +case WM_HSCROLL: +case WM_VSCROLL: + { + if ( SHORT2FROMMP( mp2 ) == SB_ENDSCROLL ) + { + WinSetFocus( HWND_DESKTOP, hwnd ); + return ( ( MRESULT ) 0 ); + } + } + break; + } + + return ( old_pm_proc( hwnd, msg, mp1, mp2 ) ); +} + +#endif + +/*START*/ +/* +Abstractions: + +Abstractions in this module encapsulate and contain state information for +certain entities that are necessary for the proper operation of this module. +The structures or classes that coorespond to these abstractions are defined +locally in this module. Code outside of this module only sees an opaque +data type, and *must* use functions in this module to manipulate the +abstractions. The developer of this module is free to put data members into +the locally defined structure or class, so that this module has the correct +state information to function properly. + +XinWindow + + this abstraction encapsulates the state and information for a created + window. also, we use an XinWindow to encapsulate the state and information + for horizontal and vertical scroll bars. scroll bars are the only controls + that Xin implements. XinWindow is also used for print windows. + + examples are: + - the handle to the native window + - a pointer to the XinWindowEventHandler + - a pointer to the previous modal window, for proper implementation of modals + - a long integer for storing application data upon request of the module that + uses Xin + + when creating an XinWindow, we pass in an XinWindowDef as an argument to + XinWindowCreate. an XinWindowDef contains all of the information necessary + to properly create either the scroll bar or the window. XinWindowType is an + enum that specifies whether to create a window or a scroll bar, and what kind + of window or scroll bar to create. The XinWindowMode determines "modality" of + the window. XinModeless is a normal window. XinModalReturn will create a window + that is the only window that can get focus and the XinWindowCreate function + will return as soon as the window is created. XinModalWait will create a window + that is the only window that can get focus and the XinWindowCreate function + will return when that window is destroyed. XinModalAutoclose will create a window + that will close automatically as soon as it loses focus. Note that XinModalReturn + and XinModalWait windows can be nested to open new modals windows. Creating + a modeless window while a modal window is open should create it without focus. + Autoclose windows can also be created "on top" of modal windows. + + one of the more difficult things to handle is our concept of a modal window. + if MFC has a modal window, we should use it. however, if we need to implement + modal windows by disabling and re-enabling windows, we will wait until later + on in this project to implement them. + + for historical reasons, in the XVT implementation, an XinWindow is, in fact, + the XVT window. this complicates the implementation because we then need to + keep state information on the window in a separate structure, and look up the + window information in a list whenever we need to access it. in the MFC + implementation, we will define a class that holds the state information on the + window, and the XinWindow should be a pointer to that class. + + windows can be enabled or disabled. a disabled window still responds to + paint events, but can't be raised, and doesn't receive character or mouse + events. + + windows can be visible or invisible. an invisible window does not generate + any paint events, nor receive character or mouse events. + + Xin does not implement child windows. + + the client area of a window is the area in which the module using Xin can draw. + the actual visible size of the window includes the border, title and menu which + are not part of the client area of the window. sometimes the + associated controls on the border are called the window decorations. + + there are two XinWindows that are automatically created before + XinAppSystemSetupInit is called. the first is the task window. this allows + the module using Xin to manipulate the task window. the second is the screen + window. This allows Xin to draw directly onto the screen. + +XinFont + + this abstraction encapsulates the data necessary to specify a font. the + font can then be passed as an argument to XinWindowTextDraw, specifying + the font that the text is drawn in. + + The XinFont can be created and set using a basic set of 'family' values, or + it can be the result of a font selection dialog. In either case, the + properties of 'bold', 'italic' and 'family' must be retrievable from the + XinFont. If the family does not match the basic set, then XinFontFamilyOther + will be used. + + fonts can be mapped or unmapped. + after a font is mapped to a window, then the module using Xin can call + functions that use the font for drawing, or to get pixel metrics of the font. + if a font is mapped to a screen window, then the pixel metrics will be very + different than if the font is mapped to a printer window. + +XinPrinterRec + + This abstraction encapsulates the data for a selected printer. + It is used for printing operations and it should be possible to + save this structure in a file and load it later. (The size of + the structure is returned by XinPrintRecordCreate.) + +XinBitmap + + this abstraction encapsulates a bitmap that can be drawn into an XinWindow. + the internal format of an XinBitmap is the BMP format. this simplifies the + process of reading bitmaps from files or dlls, then subsequently drawing the + bitmap in a window. + +XinRect + + this structure contains the four points of a rectangle (top, left, bottom, right). + it is used in calls to many Xin functions. + +XinPoint + + this structure contains the horizontal and vertical components of a point (h, v) + +Application + + the Xin module contains the main (or win_main) or whatever function is + automatically executed when an MFC application starts. the module using Xin + needs to write two things for the minimal application. a function called + XinAppSystemSetupInit is written. this function initializes a data structure that + is passed in as an argument. this data structure defines certain application + wide characteristics such as the task window title, the task window event handler, + etc. in addition, the argc and argv variables are passed to this function for + processing if the user of Xin desires. + + the sequence of actions when an application written using Xin starts is as follows: + 1) win_main (or whatever in MFC) is called by the system. + 2) win_main does any initial setup, puts argc and argv into the SystemSetup structure + 3) win_main calls XinAppSystemSetupInit + 4) data structures are set up so that when the system sends events to the MFC task + window handler, the events can be translated and sent to the Xin task window + event handler. + 5) win_main returns. + 6) windows starts sending event through to the task window event handler. + + The "use_mdi" member of XinSystemSetup indicates if MDI should be enabled. The + Window menu will be specified with the tag XI_MENU_WIN. If that tag does not + exist, the Window menu will be created at the end of the existing menu. + The Window menu should contain Cascade, Tile Horizontally, Tile Vertically, + Close All, a separator(if any windows are open), and then the list of open windows, + including a "Windows..." item to open a separate dialog if there are too many + windows for the menu. Even if the XI_MENU_WIN tag exists, the window list will need + to be added to that existing menu. Of course, MDI will also handle iconizing of + top-level windows, etc. + +Menus + + Xin implements functions to manipulate menus. the functionality includes the + ability to set up an entire menu hierarchy with one call, replace a branch of + the menu hierarchy, replace a single item, change the enabled/disabled state of + any menu item, and change the checked state af a menu item. + + there are no facilities to load menus from resources. the entire functionality + of the menu is available only through the api. + + immediately after the application starts, the user of the Xin module will + call the function that sets up the entire menu. in the MFC implementation, we + may need to define a small "stub" menu in the windows resources. this stub + menu will not have anything in it other than a file menu with an exit item. + this stub menu will be replaced before the user has any oportunity to do any + menu selections. + + there are two data structures associated with menus. an XinMenu is an array and + a count of child XinMenuItems an XinMenuItem is a branch on an XinMenu tree. it + may be the tip of a branch (a menu item that a user can select) or it may be the + parent of multiple child XinMenuItems, in which case, there is a submenu. + + The text of menus can contain a '~' to indicate the shortcut key. For example, + "~File", "~Edit", and "E~xit". + +Timers + + this allows a module using Xin to set a timer + and get an event a specified number of miliseconds in the future. upon creation + of a timer, Xin returns a timer identifier (a long + integer) that identifies the timer. the timer id is part of the data for a timer + event, so that the module using Xin can set up multiple timers, and know which + timer an event is for. the timer identifier is also used when killing the timer. + +Clipboard + + Xin abstracts operations on the clipboard. the clipboard as implemented by Xin + can have two kinds of formats on it (text, and bitmap). any module using Xin can + query the clipboard, finding whether the desired format of data is on the clipboard, + then the module can get the contents of the clipboard. + +Printing + + printing has much in common with displayed windows. before printing, a print window + needs to be created. after the print window is created, fonts can be mapped to + the print window, rectangles, lines, and text can be drawn in the window, etc. + there is one fundimental difference. after the print window is created, the module + using Xin must call XinPrintPageStart. then, the module using Xin calls + XinPrintBandNext until it returns NULL. if it is necessary to paint a band at a + time, then XinPrintBandNext will return a rectangle several times. After each return, + the area within the returned rectangle should be drawn by the module using Xin. After + XinPrintBandNext returns NULL, then the module using Xin should call XinPrintPageEnd. + This will cause the page to be printed. If the printer and the printer driver are + capable of printing the entire page at once, then XinPrintBandNext will only return + a rectangle once. + + Bob, according to a comment written by John Lilley in the report writer, banding is + no longer used for any XVT implementation. Do we really need to continue to support + banding? + + If that's true, then no. But is it true? - Bob + +*/ + +/* +Events + + Xin is an event based system. When Xin is informed of certain events in the + underlying system, then Xin should send an event to the module using Xin. the + method of sending an event to the module using Xin is as follows: + + 1) declare an automatic variable of type XinEvent + 2) set every byte in the XinEvent structure to '\0' + 3) fill in the XinEvent structure. information that needs to be specified is + the event type, and information specific to that type of event. + 4) call the event handler that the module using Xin specified when the application + was created, or when the window was created. + + Below is the set of events that Xin needs to generate: + + XinEventCreate + + This event is sent when a window is created. When the application is starting, + then this event is sent to the task window event handler, which was specified + in the function XinAppSystemSetupInit. This will be the first event for any + window. + + XinEventDestroy + + This event is sent when a window is destroyed. When the application is + terminating, then this event is sent to the task window event handler. The + window will still be valid during this event, but no other event will occur + for the window after this event. + + XinEventFocus + + This event is sent when a window is gaining or loosing keyboard focus. A + boolean variable + in the XinEvent structure indicates whether the window is gaining or losing + focus. + + XinEventResize + + This event is sent when a window is re-sized or minimized. + + XinEventPaint + + This event is sent when the windowing system needs to have the module using + Xin paint a certain region of a window. + + XinEventCloseButton + + This event is sent when the user either clicks on the close button in the + upper right corner of the window, double clicks on the window menu at the + upper left corner of the window, or selects close on the window menu. the + window should not be closed when the above actions happen. rather, Xin + lets the module using Xin close the window if it desires. + + XinEventMouseDown + + This event is sent when the user presses the mouse button within the + bounderies of a window. + + Xin reports the pressed state of the shift, control, and alt keys when + generating this event. + + XinEventMouseUp + + This event is sent when the user releases the mouse button within the + bounderies of a window. If the mouse is trapped to a window, then this + event is sent to the window in which the mouse is trapped, regardless of + whether the mouse is over that window or not. + + Xin reports the pressed state of the shift, control, and alt keys when + generating this event. + + XinEventMouseMove + + This event is sent when the user moves the mouse within the bounderies + of a window. If the mouse is trapped to a window, then this + event is sent to the window in which the mouse is trapped, regardless of + whether the mouse is over that window or not. If the mouse is trapped to + a window, and the mouse is held down, then mouse move events are continually + generated, whether the mouse is moving or not. + + Xin reports the pressed state of the shift, control, and alt keys when + generating this event. + + XinEventMouseDouble + + This event is sent when the user double clicks the mouse within the + bounderies of a window. The sequence of events when the user double clicks + and releases the mouse is: + XinEventMouseDown + XinEventMouseUp + XinEventMouseDouble + XinEventMouseUp + + Xin reports the pressed state of the shift, control, and alt keys when + generating this event. + + XinEventCharacter + + This event is sent to a window when the window has keyboard focus, and the + user presses a key in the window. Character events are translated to + Xin virtual characters. The list of virtual characters is: + + XI_KEY_DEL delete key + XI_KEY_UP up arrow key + XI_KEY_DOWN down arrow key + XI_KEY_RIGHT right arrow key + XI_KEY_LEFT left arrow key + XI_KEY_PREV page up key + XI_KEY_NEXT page down key + XI_KEY_LHOME home key + XI_KEY_LEND end key + XI_KEY_WLEFT control left arrow key + XI_KEY_WRIGHT control right arrow key + XI_KEY_BTAB shift tab key + XI_KEY_F1 function keys + XI_KEY_F2 + XI_KEY_F3 + XI_KEY_F4 + XI_KEY_F5 + XI_KEY_F6 + XI_KEY_F7 + XI_KEY_F8 + XI_KEY_F9 + XI_KEY_F10 + XI_KEY_F11 + XI_KEY_F12 + + Xin reports the pressed state of the shift, control, and alt keys when + generating this event. + + XinEventMenuCommand + + This event is sent when the user selects a menu item. The event reports the + menu tag of the selected menu item. There are no events for navigating menus. + + Xin reports the pressed state of the shift and control keys when generating + this event. + + XinEventControl + + This event is sent when the user operates a scroll bar that was set up by + Xin. The control_id in the XinEvent structure is the control id specified + when the scroll bar was created. + + In XinControlInformation, the following fields are set: + type is set to either XinWindowTypeHorizontalScrollBar or + XinWindowTypeVerticalScrollBar + win is set to the scroll bar window + v.scroll.action is set to one of XinScrollBarActionLineUp + XinScrollBarActionLineDown + XinScrollBarActionPageUp + XinScrollBarActionPageDown + XinScrollBarActionThumb + XinScrollBarActionThumbTrack + v.scroll.position is set to the current position of the thumb of the + scroll bar. + + XinEventTimer + + This event is sent when a timer expires. The module using Xin can set or + kill timers. See the discussion on timers for more details. + + XinEventQuit + + This event is sent when something or someone requests that Xin terminate. + For instance, when someone shuts down Windows95, then this event is sent. + The application, based on its state, can query the user to see if the user + wants to save changed data, discard changed data, or cancel the shutdown + operation. If, after processing input from the user, and it is still OK + to shut down, then the module using Xin should call XinAppQuitOk. If + XinAppQuitOk is not called, then the shutdown operation is aborted. + + XinEventFont + + This event does not need to be implemented in MFC. + +*/ + +/* +Drawing + + this section details the semantics and behaviors of drawing in windows. + +Mathmatical Rectangles + + Many of the Xin functions work using 'Mathmatical Rectangles'. By this, we + mean that a rectangle refers to the lines between the pixels, not the pixels + themselves. For instance, when we draw a rectangle, we specify a mathmatical + rectangle, and the pixels that get drawn are those just inside the mathmatical + rectangle. + + the following diagram needs to be viewed in a fixed font to appear correctly. + it represents a grid of pixels where the mathmatical lines between the pixels + are numbered, and the spaces represent pixels. + + 0 1 2 3 4 5 6 7 8 + 0 ----------------- + | | | | | | | | | + 1 ----------------- + | | | | | | | | | + 2 ----------------- + | | | | | | | | | + 3 ----------------- + | | | | | | | | | + 4 ----------------- + | | | | | | | | | + 5 ----------------- + | | | | | | | | | + 6 ----------------- + | | | | | | | | | + 7 ----------------- + | | | | | | | | | + ----------------- + + for instance, if we were to draw a hollow rectangle where: + top = 1 + left = 1 + right = 4 + bottom = 4 + then the following pixels would get drawn: + + 0 1 2 3 4 5 6 7 8 + 0 ----------------- + | | | | | | | | | + 1 ----------------- + | |X|X|X| | | | | + 2 ----------------- + | |X| |X| | | | | + 3 ----------------- + | |X|X|X| | | | | + 4 ----------------- + | | | | | | | | | + 5 ----------------- + | | | | | | | | | + 6 ----------------- + | | | | | | | | | + 7 ----------------- + | | | | | | | | | + ----------------- + + at various points in this module, we will refer to mathmatical rectangles, + and to properly identify the semantics of drawing functions, we will + use diagrams like the ones above. + +Clipping + + when clipping is set for a window, the drawing functions only draw within + the clipping rectangle. the rectangle for clipping is a mathmatical + rectangle. + + the functions that clip to the clipping rectangle are: + - XinWindowRectDraw + - XinWindowLineDraw + - XinWindowTextDraw + - XinWindowBitmapDraw + - XinWindowIconDraw + + note that carets do not clip to the clipping rectangle. there is a + rectangle passed in to the XinWindowCaretOn for clipping of the caret. + +Text Drawing + + The vertical metrics of a font have three components: ascent, descent, + and leading. these are pixel counts of the components of a font. + + ____ + leading ____ + + + + xxxxxx + x x + ascent x x + x x + baseline ____ xxxxx + x + descent x + ____ xxxx + + the baseline is the mathmatical line upon which most text (without + descenders) is drawn. ascent is the number of pixels above the + baseline to the top of the font. descent is the number of pixels + available for the descenders. leading is the space between the lines + of drawn text. + + There are two modes of text drawing, opaque, and not opaque. If opaque, + the background color is drawn in the entire leading/ascent/descent area. + The background color is specified by XinWindowColorTextBackSet or by + the drawing tools. + + If opaque is set to false, then only the text itself is drawn, using the + foreground color. + +XinDrawMode + + when drawing, there are two modes of drawing: copy and xor. if the draw + mode is copy, then the pixels are simply copied to the window. if the draw + mode is xor, then, if drawn on pixels equalling the back_color of the window, + drawing will attempt to produce the fore_color of the tool (pen/brush/text). + Drawing on pixels of fore_color will attempt to produce back_color. The + operation is self-reversing. the only thing that xor mode is used for is + drawing rubber band rectangles when moving columns, moving rows, resizing + columns and resizing rows. drawing in xor mode assumes that the window is + on top, and will remain on top until the rubber banding operation is complete. + +XinPen + + A pen specifies what is drawn for lines or rectangle borders. The 'width' + determines the number of pixels for the line or border. The 'pattern' may + be hollow, solid or dashed. If hollow, then no border will be drawn for a + rectangle. Solid and dashed lines are drawn using the 'fore_color'. Dashed + lines will not draw in the space between the dashes. + +XinBrush + + a brush specifies what is drawn in the interior of a rectangle. there are + two fields in an XinBrush data structure: 'pattern', and 'color'. if + 'pattern' is XinBrushHollow, then 'color' is ignored, and the interior of + the rectangle (the pixels other than those just inside the mathmatical + rectangle) are left alone. + + if 'pattern' is XinBrushSolid, then the pixels in the interior of the + rectangle are drawn in the specified color. + +XinDrawTools + + drawing tools is a convenience feature of Xin. it allows the user of Xin + to set or get the state of drawing (draw mode, brush, pen, fore color, + back color, and text opaqueness) with one function call. + +Drawing Rectangles + + There are three cases to consider when drawing rectangles: + + 1) solid pen and solid brush + 2) hollow pen and solid brush + 3) solid pen and hollow brush + + note that it does not make any sense to draw with a hollow pen and a hollow + brush. this would draw nothing. + + Example 1: solid red pen and solid blue brush + top = 1 + left = 1 + bottom = 5 + right = 5 + + this will draw a red one pixel wide rectangle just inside the + specified mathmatical rectangle. it will fill the area inside + the red rectangle of pixels with blue pixels. + + the following would be the result, r is a red pixel, b is a blue pixel + + 0 1 2 3 4 5 6 7 8 + 0 ----------------- + | | | | | | | | | + 1 ----------------- + | |r|r|r|r| | | | + 2 ----------------- + | |r|b|b|r| | | | + 3 ----------------- + | |r|b|b|r| | | | + 4 ----------------- + | |r|r|r|r| | | | + 5 ----------------- + | | | | | | | | | + 6 ----------------- + | | | | | | | | | + 7 ----------------- + | | | | | | | | | + ----------------- + + Example 2: hollow pen and solid blue brush + top = 1 + left = 1 + bottom = 5 + right = 5 + + this will fill the mathmatical rectangle with blue pixels. + + the following would be the result, b is a blue pixel + + 0 1 2 3 4 5 6 7 8 + 0 ----------------- + | | | | | | | | | + 1 ----------------- + | |b|b|b|b| | | | + 2 ----------------- + | |b|b|b|b| | | | + 3 ----------------- + | |b|b|b|b| | | | + 4 ----------------- + | |b|b|b|b| | | | + 5 ----------------- + | | | | | | | | | + 6 ----------------- + | | | | | | | | | + 7 ----------------- + | | | | | | | | | + ----------------- + + Example 3: solid blue pen and hollow brush + top = 1 + left = 1 + bottom = 5 + right = 5 + + this will draw a blue rectangle, one pixel wide, just inside + the mathmatical rectangle. + + the following would be the result, b is a blue pixel + + 0 1 2 3 4 5 6 7 8 + 0 ----------------- + | | | | | | | | | + 1 ----------------- + | |b|b|b|b| | | | + 2 ----------------- + | |b| | |b| | | | + 3 ----------------- + | |b| | |b| | | | + 4 ----------------- + | |b|b|b|b| | | | + 5 ----------------- + | | | | | | | | | + 6 ----------------- + | | | | | | | | | + 7 ----------------- + | | | | | | | | | + ----------------- + +Drawing Lines + + There are three cases to consider when drawing lines: + + 1) horizontal lines + 2) vertical lines + 3) diagonal lines + + Example 1: a horizontal line + from + horizontal = 1 + vertical = 1 + to + horizontal = 6 + vertical = 1 + + this will draw the row of pixels just below the mathmatical line. + + 0 1 2 3 4 5 6 7 8 + 0 ----------------- + | | | | | | | | | + 1 ----------------- + | |x|x|x|x|x| | | + 2 ----------------- + | | | | | | | | | + 3 ----------------- + | | | | | | | | | + 4 ----------------- + | | | | | | | | | + 5 ----------------- + | | | | | | | | | + 6 ----------------- + | | | | | | | | | + 7 ----------------- + | | | | | | | | | + ----------------- + + Example 2: a vertical line + from + horizontal = 1 + vertical = 1 + to + horizontal = 1 + vertical = 7 + + this will draw the row of pixels just to the right of + the mathmatical line. + + 0 1 2 3 4 5 6 7 8 + 0 ----------------- + | | | | | | | | | + 1 ----------------- + | |x| | | | | | | + 2 ----------------- + | |x| | | | | | | + 3 ----------------- + | |x| | | | | | | + 4 ----------------- + | |x| | | | | | | + 5 ----------------- + | |x| | | | | | | + 6 ----------------- + | |x| | | | | | | + 7 ----------------- + | | | | | | | | | + ----------------- + + Example 3: a diagonal line + from + horizontal = 1 + vertical = 1 + to + horizontal = 4 + vertical = 4 + + taking the mathmatical rectangle formed by placing the two points + at oposite corners, the two pixels just inside the corners of the + mathmatical rectangle are drawn, with some pixels in between. if + the absolute value of the rise and the run are equal, i.e. the line + is a diagonal line 45 degrees off of horizontal and vertical, then + a straight diagonal line is drawn. + + + 0 1 2 3 4 5 6 7 8 + 0 ----------------- + | | | | | | | | | + 1 ----------------- + | |x| | | | | | | + 2 ----------------- + | | |x| | | | | | + 3 ----------------- + | | | |x| | | | | + 4 ----------------- + | | | | | | | | | + 5 ----------------- + | | | | | | | | | + 6 ----------------- + | | | | | | | | | + 7 ----------------- + | | | | | | | | | + ----------------- + + Note: the adjustments that we need to make for MFC probably are the same as + the adjustments that are needed to be made for the Windows version of XVT. + + +*/ + +/* +Other Notes + +Mouse Trapping + + the mouse can be trapped to a window. when the mouse is trapped, all mouse + events until the mouse is released go to the window in which the mouse is + trapped. this ensures that if a window receives a mouse down event, it will + be guarenteed to receive the mouse up event. + + while the mouse is trapped, if the mouse button is down, the window is + guarenteed to receive mouse move events even if the mouse is not moving. this + facilitates the behavior where the user is selecting text, drags the mouse + outside of the region where they are selecting text, and the text continually + scrolls until the user drags the mouse back into the region, or the user + releases the mouse button. + +*/ + +/* +allocates memory on the heap. the size of the allocated block is indicated +by the argument 'size'. returns a pointer to the allocated memory. +*/ +void * +XinMemoryAlloc( size_t size ) +{ + return malloc( size ); +} + +/* +frees memory previously allocated by XinMemoryAlloc. the pointer to the +memory is passed in as the argument 'ptr'. +*/ +void +XinMemoryFree( void *ptr ) +{ + free( ptr ); +} + +/* +reallocates memory previously allocated by XinMemoryAlloc. the new size of +the allocated block is indicated by the argument 'size'. the pointer to be +reallocated is passed in as the argument 'ptr'. returns a pointer to the +allocated memory. +*/ +void * +XinMemoryRealloc( void *ptr, size_t size ) +{ + return realloc( ptr, size ); +} + +/* +allocates and clears memory on the heap. the size of the allocated block +is indicated by the argument 'size'. returns a pointer to the allocated memory. +*/ +void * +XinMemoryZeroAlloc( size_t size ) +{ + void *ptr = malloc( size ); + + memset( ptr, 0, size ); + return ptr; +} + +/* +puts up a modal dialog box with a message and up to three buttons. gets a +response from the user and returns XinResponse1 if button 1 is pressed. +returns XinResponse2 if button2 is pressed. returns XinResponse3 if button3 +is pressed. + +the argument 'Btn3' may be NULL, in which case only two buttons are put into +the dialog box. + +the arguments 'Btn2' and 'Btn3' may be NULL, in which case only one button +is put into the dialog box. + +the message is specified by a format and a variable number of arguments, +similar to the function printf +*/ +XinResponse +XinDialogAsk( char *Btn1, char *Btn2, char *Btn3, char *format,... ) +{ +/*END*/ + ASK_RESPONSE ask_response; + va_list argptr; + char button1[200], button2[200], button3[200]; + + XinInitBuffer( ); + va_start( argptr, format ); + vsprintf( xin_buffer, format, argptr ); + va_end( argptr ); + xin_buffer[200] = '\0'; + if (Btn1 != NULL && strlen(Btn1) >= 200) + { + strncpy( button1, Btn1, 199 ); + button1[199] = '\0'; + Btn1 = button1; + } + if (Btn2 != NULL && strlen(Btn2) >= 200) + { + strncpy( button2, Btn2, 199 ); + button2[199] = '\0'; + Btn2 = button2; + } + if (Btn3 != NULL && strlen(Btn3) >= 200) + { + strncpy( button3, Btn3, 199 ); + button3[199] = '\0'; + Btn3 = button3; + } + ask_response = xvt_dm_post_ask( Btn1, Btn2, Btn3, xin_buffer ); + switch ( ask_response ) + { + case RESP_DEFAULT: + return XinResponse1; + case RESP_2: + return XinResponse2; + case RESP_3: + return XinResponse3; + } + return XinResponse1; +/*START*/ +} + +/* +puts up an error message modal dialog box. + +the message is specified by a format and a variable number of arguments, +similar to the function printf +*/ +void +XinDialogError( char *format,... ) +{ +/*END*/ + va_list argptr; + + XinInitBuffer( ); + va_start( argptr, format ); + vsprintf( xin_buffer, format, argptr ); + va_end( argptr ); + xin_buffer[200] = '\0'; + xvt_dm_post_error( xin_buffer ); +/*START*/ +} + +/* +puts up a fatal error message dialog box. this function should not return, +but should exit the application. + +this function should not allocate any memory, as this function might have +been called because the heap is corrupted. + +the message is specified by a format and a variable number of arguments, +similar to the function printf +*/ +void +XinDialogFatal( char *format,... ) +{ +/*END*/ + va_list argptr; + + XinInitBuffer( ); + va_start( argptr, format ); + vsprintf( xin_buffer, format, argptr ); + va_end( argptr ); + xin_buffer[200] = '\0'; + xvt_dm_post_fatal_exit( xin_buffer ); +/*START*/ +} + +/*END*/ +/* This is for a silly bug with openfile dialogs under windows. */ +#if XIWS == XIWS_WIN +static void +open_file_hook( OPENFILENAME * lpofn ) +{ + lpofn->Flags |= OFN_PATHMUSTEXIST; +} + +#endif + +/*START*/ +/* +this function puts up a file open or a file save modal dialog box. + +the string in the argument 'message' is put into the dialog box as a prompt +for the user. + +if the argument 'type' is XinOpenFileDialog then the open file dialog box is +put up. this allows the user to specify a name of a file to be opened for +reading. the user is supplied with a list of files to choose from. the +user also may change directories to search for the desired file. if a valid +filename is specifed by the user, then this function returns XinFileGood. if an +error occurs, then this function returns XinFileBad after an appropriate error +message is displayed. +if the user canceled the dialog box without specifying a file name, then this +function returns XinFileCancel. upon entry to the function, the argument 'spec' +specifies the file type (a three character extension for the MFC implementation), +the starting directory and the starting file name if desired. see the definition +of XinFileSpec for further details. when this function returns, if XinFileGood +is the returned status, then the argument 'spec' is filled in with the specified +file and directory. + +if the argument type is XinSaveFileDialog then the save file dialog box is +put up. this allows the user to specify a name of a file to be created, or +opened for writing. the user is supplied with a list of files to choose from. the +user also may change directories to search for the desired file. if a valid +filename is specifed by the user, then this function returns XinFileGood. if an +error occurs, then this function returns XinFileBad after an appropriate message +is displayed. +if the user canceled the dialog box without specifying a file name, then this +function returns XinFileCancel. upon entry to the function, the argument 'spec' +specifies the file type (a three character extension for the MFC implementation), +the starting directory and the starting file name if desired. see the definition +of XinFileSpec for further details. when this function returns, if XinFileGood +is the returned status, then the argument 'spec' is filled in with the specified +file and directory. + +the implementation for MFC should simply put up the standard open or save file +dialog. +*/ +XinFileResult +XinDialogFile( char *message, XinFileSpec * spec, XinFileDialogType type ) +{ +/*END*/ + FL_STATUS result; + FILE_SPEC xvt_spec; + +#if XIWS == XIWS_WIN + long old_hook; + +#endif + +#if XIWS == XIWS_MAC + strncpy( xvt_spec.type, spec->type, sizeof( xvt_spec.type ) - 1 ); + strncpy( xvt_spec.name, spec->file_name, SZ_FNAME ); + xvt_spec.name[SZ_FNAME] = '\0'; +#else + if ( type == XinOpenFileDialog ) + { + char *dot_ptr = strchr( spec->file_name, '.' ); + + if ( dot_ptr != NULL ) + strcpy( xvt_spec.type, dot_ptr + 1 ); + else { + if (spec->type != NULL) + strcpy( xvt_spec.type, spec->type ); + else + xvt_spec.type[0] = '\0'; + } + } + else + { + strncpy( xvt_spec.type, spec->type, sizeof( xvt_spec.type ) - 1 ); + strncpy( xvt_spec.name, spec->file_name, SZ_FNAME ); + xvt_spec.name[SZ_FNAME] = '\0'; + } +#endif + xvt_fsys_convert_str_to_dir( ( char * ) spec->directory, &xvt_spec.dir ); +#if XIWS == XIWS_WIN + old_hook = xvt_vobj_get_attr( NULL_WIN, ATTR_WIN_OPENFILENAME_HOOK ); + xvt_vobj_set_attr( NULL_WIN, ATTR_WIN_OPENFILENAME_HOOK, + ( long ) open_file_hook ); +#endif + if ( type == XinOpenFileDialog ) + result = xvt_dm_post_file_open( &xvt_spec, message ); + else + result = xvt_dm_post_file_save( &xvt_spec, message ); +#if XIWS == XIWS_WIN + xvt_vobj_set_attr( NULL_WIN, ATTR_WIN_OPENFILENAME_HOOK, old_hook ); +#endif + switch ( result ) + { + case FL_OK: + xvt_fsys_convert_dir_to_str( &xvt_spec.dir, ( char * ) spec->directory, + sizeof( XinDirectory ) ); + strncpy( spec->file_name, xvt_spec.name, XI_FILE_MAX ); + spec->file_name[XI_FILE_MAX] = '\0'; + return XinFileGood; + case FL_CANCEL: + return XinFileCancel; + case FL_BAD: + return XinFileBad; + } + return XinFileBad; +/*START*/ +} + +/* +this function puts up the standard font selection dialog box. upon selection of +a font by the user, the argument 'font' is set to the specified font. + +if the user canceled, then this function returns FALSE. if the user specified +a font, then this function returns TRUE. +*/ +BOOLEAN +XinDialogFont( XinFont * font ) +{ +/*END*/ + if ( !xvt_dm_post_font_sel( NULL_WIN, font->xvt_fntid, NULL, 0L ) ) + return FALSE; + font->from_xvt_font = TRUE; + XinFontNativeConvert( font ); + return TRUE; +/*START*/ +} + +/* +puts up a modal dialog box that displays a note with a single "OK" button. + +the message is specified by a format and a variable number of arguments, +similar to the function printf +*/ +void +XinDialogNote( char *format,... ) +{ +/*END*/ + va_list argptr; + + XinInitBuffer( ); + va_start( argptr, format ); + vsprintf( xin_buffer, format, argptr ); + va_end( argptr ); + xin_buffer[200] = '\0'; + xvt_dm_post_note( xin_buffer ); +/*START*/ +} + +/* +this function puts up a printer setup dialog box. this allows the user to +select a printer and setup options for that printer. + +this function should put up the standard printer setup dialog box in MFC. + +this function fills in an XinPrintRecord, which is an abstraction implemented +locally in this module. see the abstraction discussion on XinPrintRecord above. +*/ +BOOLEAN +XinDialogPrinterSetup( XinPrintRecord * rec ) +{ +/*END*/ + return xvt_dm_post_page_setup( ( PRINT_RCD * ) rec ); +/*START*/ +} + +/* +this function puts up a dialog box with a message, and gets a string response +from the user. the argument 'message' contains the prompt for the user. +the argument 'response' points to a character buffer, which is filled in +with the user's response. the argument 'response_len' contains the length +of the character array pointed to by 'response'. this function should never +copy more characters into 'response' than 'response_len' to avoid overwriting +memory and corrupting the heap. + +this function returns the value in 'response' if the user typed a string and +pressed OK. if the user pressed cancel, then this function returns NULL. +*/ +char * +XinDialogStringPrompt( char *message, char *response, int response_len ) +{ +/*END*/ + return xvt_dm_post_string_prompt( message, response, response_len ); +/*START*/ +} + +/* +each XinWindow can have an arbitrary long integer associated with it for +storing of state data with the window. typically, the module that uses +Xin will allocate memory for data, fill in the data structure, and pass +the allocated pointer to XinWindowAppDataSet, casting the pointer to a +long in the call. + +this function simply sets the app data field in the XinWindow abstraction +to the argument 'AppData'. +*/ +void +XinWindowAppDataSet( XinWindow Win, long AppData ) +{ +/*END*/ + xvt_vobj_set_data( ( WINDOW ) Win, AppData ); +/*START*/ +} + +/* +this function returns a value previously passed to XinWindowAppDataSet for +the specified window. +*/ +long +XinWindowAppDataGet( XinWindow Win ) +{ +/*END*/ + return xvt_vobj_get_data( ( WINDOW ) Win ); +/*START*/ +} + +void +XinWindowArcDraw( XinWindow Win, XinRect* rctp, XinPoint* start, XinPoint* stop ) +{ + RCT r; + + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->bottom; + xvt_dwin_draw_arc( (WINDOW) Win, &r, start->h, start->v, stop->h, stop->v ); +} + +/* +this function draws the bitmap specified in the argument 'bitmap' into the +window specified by 'win'. + +'source' specifies a mathmatical rectangle which may be a subsection of the +specified bitmap. if 'source' is the same size as the bitmap, then the entire +bitmap is drawn. + +'dest' specifies the destination rectangle in the window. + +if 'source' and 'dest' are not the same size, then this function scales the +bitmap to fit. +*/ +void +XinWindowBitmapDraw( XinWindow win, XinBitmap * bitmap, XinRect * dest, XinRect * source ) +{ +/*END*/ + xvt_dwin_draw_image( ( WINDOW ) win, bitmap->image, ( RCT * ) dest, ( RCT * ) source ); +/*START*/ +} + +/*END*/ +static PAT_STYLE +BrushPatternToPAT( XinBrushPattern Pattern ) +{ + switch ( Pattern ) + { + case XinBrushSolid: + return PAT_SOLID; + case XinBrushHollow: + return PAT_HOLLOW; + default: + break; + } + return PAT_SOLID; +} + +static PAT_STYLE +PenPatternToPAT( XinPenPattern Pattern ) +{ + switch ( Pattern ) + { + case XinPenSolid: + return PAT_SOLID; + case XinPenHollow: + return PAT_HOLLOW; + case XinPenDashed: + return PAT_RUBBER; + default: + break; + } + return PAT_SOLID; +} + +static XinBrushPattern +PATToBrushPattern( PAT_STYLE pat ) +{ + switch ( pat ) + { + case PAT_SOLID: + return XinBrushSolid; + case PAT_HOLLOW: + return XinBrushHollow; + default: + break; + } + return XinBrushSolid; +} + +static XinPenPattern +PATToPenPattern( PAT_STYLE pat ) +{ + switch ( pat ) + { + case PAT_SOLID: + return XinPenSolid; + case PAT_HOLLOW: + return XinPenHollow; + case PAT_RUBBER: + return XinPenDashed; + default: + break; + } + return XinPenSolid; +} + +/*START*/ + +/* +this function sets the brush for subsequent rectangle drawing operations. + +see the drawing discussion above for details on drawing. +*/ +void +XinWindowBrushSet( XinWindow win, XinBrush * brush ) +{ +/*END*/ + CBRUSH cbrush; + +#ifdef NEED_PATCH +/* Hack for OS2 */ +/* The calls to XinWindowDrawToolsNormalGet and DrawToolsSet + cause a update problem in the link list edit window */ +#if XIWS == XIWS_PM + if ( brush->fore_color == XI_COLOR_LTGRAY ) + { + XinBrush hollow_cbrush; + XinRect rct; + + /* Bad bug with XVT/PM, needs this before can draw COLOR_LTGRAY */ + XinWindowDrawToolsNormalGet( &t ); + win_set_draw_ctools( win, &t ); + hollow_cbrush.color = XI_COLOR_WHITE; + hollow_cbrush.pat = XinPatternHollow; + win_set_cbrush( win, &hollow_cbrush ); + rct.top = 0; + rct.left = 0; + rct.bottom = 0; + rct.right = 0; + xi_draw_rect( win, &rct ); + } +#endif +#if XIWS == XIWS_XM || XIWS == XIWS_WXGTK + if ( brush->fore_color == XI_COLOR_LTGRAY ) + { + /* X GRAY SCALE HACK */ + XinWindowBackColorSet( win, XI_COLOR_WHITE ); + { + XinDrawTools ct; + + XinWindowDrawToolsGet( win, &ct ); + ct.opaque_text = FALSE; + XinWindowDrawToolsSet( win, &ct ); + xi_draw_text( win, 0, 0, " ", -1 ); + } + } +#endif +#endif + + cbrush.color = brush->fore_color; + cbrush.pat = BrushPatternToPAT( brush->pattern ); +#if XIWS == XIWS_WM + xi_fix_color( &cbrush.color ); +#endif + xvt_dwin_set_cbrush( ( WINDOW ) win, &cbrush ); +/*START*/ +} + +/*END*/ +static BOOLEAN caret_is_on = FALSE; + +/*START*/ +/* +the caret is the blinking vertical line that indicates the current insertion +point when editing text. + +this function turns off the caret in the specified window. +*/ +void +XinWindowCaretOff( XinWindow win ) +{ +/*END*/ +#if XIWS == XIWS_WIN + PNT p; + + if ( !caret_is_on ) + return; + p.h = -100; + p.v = -100; + xvt_win_set_caret_pos( ( WINDOW ) win, p ); +#endif + caret_is_on = FALSE; + xvt_win_set_caret_visible( ( WINDOW ) win, FALSE ); +/*START*/ +} + +/* +this function turns on a caret in the specified window 'win' + +'x' and 'y' specify the position of the bottom of the caret. + +'height' specifies the height of the caret. + +'assumed_back_color' is not used for the MFC implementation. + +'clip_rct' specifies a clipping rectangle for the caret. If the caret is +totally outside of the clipping rectangle, then the caret is not turned on. +if the caret is completely inside of the clipping rectangle, then the caret +is turned on normally. if the caret is partially outside of the clipping +rectangle, then the actual height is reduced, and position of the caret is +modified so that it appears as if the caret is clipped by the clipping rectangle. +*/ +void +XinWindowCaretOn( XinWindow win, int x, int y, int height, XinColor assumed_back_color, + XinRect * clip_rct ) +{ +/*END*/ + PNT p; + int dist_from_top; + + NOREF( assumed_back_color ); + if ( caret_is_on ) + return; + caret_is_on = TRUE; + + p.h = x; + p.v = y; + + /* If the caret base is outsde the bottom of the clip rectangle - set the + * caret base to the clip bottom and adjust the caret height */ + + if ( clip_rct ) + { + if ( p.v > clip_rct->bottom ) + { + int adjust = p.v - clip_rct->bottom; + + height = height - adjust; + + p.v = clip_rct->bottom; + } + + /* If the caret height is taller than the clip rectangle adjust it */ + + dist_from_top = p.v - clip_rct->top; + + if ( height > dist_from_top ) + height = dist_from_top; + } + + /* The calculations above could result in a height of 0 or less if that is + * the case there is no caret */ + if ( height > 0 ) + { +#if 0 + { /* This patches a bug in the caret position in + * XVT/WIN */ + int leading, + ascent, + descent; + + xvt_dwin_get_font_metrics( ( WINDOW ) win, &leading, &ascent, &descent ); + p.v -= height - ( leading + ascent + descent ); + } +#endif + xvt_win_set_caret_size( ( WINDOW ) win, XIN_CARET_WIDTH, height ); + xvt_win_set_caret_pos( ( WINDOW ) win, p ); + xvt_win_set_caret_visible( ( WINDOW ) win, TRUE ); + } +/*START*/ +} + +/*END*/ +/* +non-xvt versions do not need to support this function +*/ +void +XinWindowCheckBox( XinWindow Win, BOOLEAN Check ) +{ +/* +#if XIWS != XIWS_XM +*/ + xvt_ctl_set_checked( ( WINDOW ) Win, Check ); +/* +#endif +*/ +} + +/* +non-xvt versions do not need to support this function +*/ +void +XinWindowCheckRadioButton( XinWindow Win, XinWindow * Wins, int NbrWindows ) +{ + xvt_ctl_check_radio_button( ( WINDOW ) Win, ( WINDOW * ) Wins, NbrWindows ); +} + +/*START*/ +/* +this function gets the current clipping rectangle for the specified window. + +the caller of this function passes in a pointer to a rectangle for the argument +'rctp'. this rectangle is filled in with the clipping region. + +this function always returns TRUE. + +see the discussion on drawing for further details. +*/ +BOOLEAN +XinWindowClipGet( XinWindow win, XinRect * rctp ) +{ +/*END*/ + ( XinRect * ) xvt_dwin_get_clip( ( WINDOW ) win, ( RCT * ) rctp ); + /*** TODO: if rctp is very large, return FALSE ***/ + return TRUE; +/*START*/ +} + +/* +this function sets the clipping rectangle for the specified window. + +'rctp' points to the desired mathmatical clipping rectangle. +*/ +void +XinWindowClipSet( XinWindow win, XinRect * rctp ) +{ +/*END*/ + xvt_dwin_set_clip( ( WINDOW ) win, ( RCT * ) rctp ); +/*START*/ +} + +/* +this function sets the background color to use when drawing text in +opaque mode. + +see the drawing discussion above for additional details on opaque drawing +of text. +*/ +void +XinWindowColorTextBackSet( XinWindow win, XinColor color ) +{ +/*END*/ +#if XIWS == XIWS_WM + xi_fix_color( &color ); +#endif + xvt_dwin_set_back_color( ( WINDOW ) win, color ); +/*START*/ +} + +/* +this function sets the foreground color to use when drawing text in +both opaque and non-opaque mode. + +see the drawing discussion above for details on drawing text. +*/ +void +XinWindowColorTextForeSet( XinWindow win, XinColor color ) +{ +/*END*/ + xvt_dwin_set_fore_color( ( WINDOW ) win, color ); +/*START*/ +} + +/*END*/ +static XinScrollBarAction +ConvertWhat( SCROLL_CONTROL scroll_control ) +{ + switch ( scroll_control ) + { +case SC_LINE_UP: + return XinScrollBarActionLineUp; + case SC_LINE_DOWN: + return XinScrollBarActionLineDown; + case SC_PAGE_UP: + return XinScrollBarActionPageUp; + case SC_PAGE_DOWN: + return XinScrollBarActionPageDown; + case SC_THUMB: + return XinScrollBarActionThumb; + case SC_THUMBTRACK: + return XinScrollBarActionThumbTrack; + default: + break; + } + return XinScrollBarActionLineUp; +} + +XinFont * +XinFontXvtConvert( void *font_id ) +{ + XinFont *font = XinMemoryZeroAlloc( sizeof( XinFont ) ); + + font->xvt_fntid = xvt_font_create( ); + xvt_font_copy( font->xvt_fntid, ( XVT_FNTID ) font_id, + ( unsigned long ) XVT_FA_ALL ); + font->from_xvt_font = TRUE; + return font; +} + +void * +XinFontXvtConvertBack( XinFont * font ) +{ + return font->xvt_fntid; +} + +void +XinFontXvtDestroy( void *font_id ) +{ + xvt_font_destroy( ( XVT_FNTID ) font_id ); +} + +#define FONT_ATTR_SIZE 256 /* family or native_desc size */ + +/* +This function fills out a font based on its native fontid, perhaps one from a font dialog. +Afterwards, the font is guaranteed to respond correctly to family, size, bold, and italic +inquiries, except that family may be XinFontFamilyOther. +*/ +static int xin_stricmp( const char* s1, const char* s2 ) +{ + while (*s1 && *s2 && toupper(*s1) == toupper(*s2)) + { + s1++; + s2++; + } + return toupper(*s2) - toupper(*s1); +} + +static char *xin_family_name_times = NULL; +static char *xin_family_name_fixed = NULL; +static char *xin_family_name_helvetica = NULL; +static char *xin_family_name_system = NULL; +static BOOLEAN xin_family_names_initialized = FALSE; + +void +XinFontNativeConvert( XinFont * font ) +{ + if (font->from_xvt_font) + { + char buf1[FONT_ATTR_SIZE]; + XinFontFamily family; + unsigned long attrib; + + if (!xin_family_names_initialized) + { /* We need to know what XVT is really mapping the fonts to. */ + char buf[100]; + XVT_FNTID font_id = xvt_font_create(); + WINDOW font_win; + XinWindowDef Def; + XinRect rect = {-1000, -1000, -900, -900}; + + MEMCLEAR( Def ); + Def.type = XinWindowTypeDocument; + Def.border_style = XinBorderFixed; + Def.p_rect = ▭ + Def.title = ""; + font_win = (WINDOW)XinWindowCreate( &Def ); + xvt_font_map( font_id, font_win ); + if (xvt_font_get_family_mapped( font_id, buf, 99 )) + { + xin_family_name_system = (char*)XinMemoryAlloc( strlen( buf ) + 1 ); + strcpy( xin_family_name_system, buf ); + } + xvt_font_set_family( font_id, "times" ); + xvt_font_map( font_id, font_win ); + if (xvt_font_get_family_mapped( font_id, buf, 99 )) + { + xin_family_name_times = (char*)XinMemoryAlloc( strlen( buf ) + 1 ); + strcpy( xin_family_name_times, buf ); + } + xvt_font_set_family( font_id, "fixed" ); + xvt_font_map( font_id, font_win ); + if (xvt_font_get_family_mapped( font_id, buf, 99 )) + { + xin_family_name_fixed = (char*)XinMemoryAlloc( strlen( buf ) + 1 ); + strcpy( xin_family_name_fixed, buf ); + } + xvt_font_set_family( font_id, "helvetica" ); + xvt_font_map( font_id, font_win ); + if (xvt_font_get_family_mapped( font_id, buf, 99 )) + { + xin_family_name_helvetica = (char*)XinMemoryAlloc( strlen( buf ) + 1 ); + strcpy( xin_family_name_helvetica, buf ); + } + xvt_font_destroy( font_id ); + XinWindowDestroy( (XinWindow)font_win ); + xin_family_names_initialized = TRUE; + } + + if ( !xvt_font_get_family( font->xvt_fntid, buf1, FONT_ATTR_SIZE ) ) + return; + + if (xin_stricmp( buf1, xin_family_name_system ) == 0) + family = XinFontFamilySystem; + else if (xin_stricmp( buf1, xin_family_name_fixed ) == 0) + family = XinFontFamilyFixed; + else if (xin_stricmp( buf1, xin_family_name_times ) == 0) + family = XinFontFamilyTimes; + else if (xin_stricmp( buf1, xin_family_name_helvetica) == 0) + family = XinFontFamilyHelvetica; + else + family = XinFontFamilyOther; + font->family = family; + attrib = xvt_font_get_style( font->xvt_fntid ); + font->italic = (attrib & XVT_FS_ITALIC ? TRUE : FALSE); + font->bold = (attrib & XVT_FS_BOLD ? TRUE : FALSE); + font->size = (int)xvt_font_get_size( font->xvt_fntid ); + font->from_xvt_font = FALSE; + } +} + +static BOOLEAN +ConvertEvent( EVENT * ep, XinEvent * xiep ) +{ + BOOLEAN retval = TRUE; + + switch ( ep->type ) + { + case E_CREATE: + xiep->type = XinEventCreate; + break; + case E_DESTROY: + xiep->type = XinEventDestroy; + break; + case E_FOCUS: + xiep->type = XinEventFocus; + xiep->v.focus.active = ep->v.active; + break; + case E_SIZE: + xiep->type = XinEventResize; + xiep->v.resize.width = ep->v.size.width; + xiep->v.resize.height = ep->v.size.height; + break; + case E_UPDATE: + xiep->type = XinEventPaint; + xiep->v.paint.rect = *( XinRect * ) & ep->v.update.rct; + break; + case E_CLOSE: + xiep->type = XinEventCloseButton; + break; + case E_MOUSE_DOWN: + xiep->type = XinEventMouseDown; + xiep->v.mouse.where.v = ep->v.mouse.where.v; + xiep->v.mouse.where.h = ep->v.mouse.where.h; + xiep->v.mouse.shift = ep->v.mouse.shift; + xiep->v.mouse.control = ep->v.mouse.control; + xiep->v.mouse.button = ep->v.mouse.button; + break; + case E_MOUSE_UP: + xiep->type = XinEventMouseUp; + xiep->v.mouse.where.v = ep->v.mouse.where.v; + xiep->v.mouse.where.h = ep->v.mouse.where.h; + xiep->v.mouse.shift = ep->v.mouse.shift; + xiep->v.mouse.control = ep->v.mouse.control; + xiep->v.mouse.button = ep->v.mouse.button; +#ifndef NO_PRIMARY_SELECTION +#if XIWS == XIWS_XM + if ( xiep->v.mouse.button == 2 ) + get_primary_selection( itf, win ); +#endif +#endif + break; + case E_MOUSE_MOVE: + xiep->type = XinEventMouseMove; + xiep->v.mouse.where.v = ep->v.mouse.where.v; + xiep->v.mouse.where.h = ep->v.mouse.where.h; + xiep->v.mouse.shift = ep->v.mouse.shift; + xiep->v.mouse.control = ep->v.mouse.control; + xiep->v.mouse.button = ep->v.mouse.button; + break; + case E_MOUSE_DBL: + xiep->type = XinEventMouseDouble; + xiep->v.mouse.where.v = ep->v.mouse.where.v; + xiep->v.mouse.where.h = ep->v.mouse.where.h; + xiep->v.mouse.shift = ep->v.mouse.shift; + xiep->v.mouse.control = ep->v.mouse.control; + xiep->v.mouse.button = ep->v.mouse.button; + break; + case E_CHAR: + xiep->type = XinEventCharacter; + xiep->v.character.ch = ep->v.chr.ch; +#if XIWS == XIWS_WM + /* TODO ep->v.chr.shift and ep->v.chr.control are not set properly for + * XVT/CH */ + xiep->v.character.shift = FALSE; + xiep->v.character.control = FALSE; +#else + xiep->v.character.shift = ep->v.chr.shift; + xiep->v.character.control = ep->v.chr.control; +#endif +#if XIWS == XIWS_WIN + if ( xiep->v.character.ch == '\t' && xiep->v.character.shift ) + /* ignore bogus shift-tab from XVT */ + retval = FALSE; +#endif + break; + case E_HSCROLL: + xiep->type = XinEventHScroll; + xiep->v.scroll.action = ConvertWhat( ep->v.scroll.what ); + xiep->v.scroll.position = ep->v.scroll.pos; + break; + case E_VSCROLL: + xiep->type = XinEventVScroll; + xiep->v.scroll.action = ConvertWhat( ep->v.scroll.what ); + xiep->v.scroll.position = ep->v.scroll.pos; + break; + case E_COMMAND: + xiep->type = XinEventMenuCommand; + xiep->v.menu_command.tag = ep->v.cmd.tag; + xiep->v.menu_command.shift = ep->v.cmd.shift; + xiep->v.menu_command.control = ep->v.cmd.control; + break; + case E_FONT: + xiep->type = XinEventFont; + xiep->v.font.font = XinFontXvtConvert( ep->v.font.font_id ); + XinFontNativeConvert( xiep->v.font.font ); + break; + case E_CONTROL: + xiep->type = XinEventControl; + xiep->v.control.control_id = ep->v.ctl.id; + switch ( ep->v.ctl.ci.type ) + { + /* non-xvt versions do not need to support buttons, radio buttons, + * and check boxes */ + case WC_PUSHBUTTON: + xiep->v.control.ctrl_info.type = XinWindowTypeButton; + break; + case WC_RADIOBUTTON: + xiep->v.control.ctrl_info.type = XinWindowTypeRadioButton; + break; + case WC_CHECKBOX: + xiep->v.control.ctrl_info.type = XinWindowTypeCheckBox; + break; + case WC_HSCROLL: + xiep->v.control.ctrl_info.win = ( XinWindow ) ep->v.ctl.ci.win; + xiep->v.control.ctrl_info.type = XinWindowTypeHorizontalScrollBar; + xiep->v.control.ctrl_info.v.scroll.action = ConvertWhat( ep->v.ctl.ci.v.scroll.what ); + xiep->v.control.ctrl_info.v.scroll.position = ep->v.ctl.ci.v.scroll.pos; + break; + case WC_VSCROLL: + xiep->v.control.ctrl_info.win = ( XinWindow ) ep->v.ctl.ci.win; + xiep->v.control.ctrl_info.type = XinWindowTypeVerticalScrollBar; + xiep->v.control.ctrl_info.v.scroll.action = ConvertWhat( ep->v.ctl.ci.v.scroll.what ); + xiep->v.control.ctrl_info.v.scroll.position = ep->v.ctl.ci.v.scroll.pos; + break; + default: + break; + } + break; + case E_TIMER: + xiep->type = XinEventTimer; + xiep->v.timer.id = ep->v.timer.id; + break; + case E_QUIT: + xiep->type = XinEventQuit; + xiep->v.quit.query = ep->v.query; + break; + case E_HELP: + xiep->type = XinEventHelp; + xiep->v.help.obj = ( XinWindow ) ep->v.help.obj; + xiep->v.help.tag = ep->v.help.tag; + xiep->v.help.topic_id = ( long ) ep->v.help.tid; + break; + case E_USER: + xiep->type = XinEventUser; + xiep->v.user.id = ep->v.user.id; + xiep->v.user.ptr = ep->v.user.ptr; + break; + default: + retval = FALSE; + break; + } + return retval; +} + +long +XinXvtEventHandler( WINDOW win, EVENT * ep ) +{ + WindowInfo *ehlt; + EVENT fake_event; + + assert4( ep->type != E_CREATE || win != TASK_WIN || xin_teh != NULL, "", + 20095, "XinAppSystemSetupInit was not provided." ); + if ( ep->type == E_CREATE && xin_teh ) + { + XinXvtWindowRegister( ( XinWindow ) win, xin_teh ); + XinWindowCreateFinish( ( XinWindow ) win ); + xin_teh = NULL; + } + + /* Modal behavior */ +#if XIWS == XIWS_MAC || XIWS == XIWS_XM || XIWS == XIWS_PM || XIWS == XIWS_WM || XIWS == XIWS_WXGTK +#if XIWS == XIWS_MAC + if ( xin_modal_win == ( XinWindow ) win + && ep->type == E_FOCUS && !ep->v.active ) + XinWindowFrontSet( xin_modal_win ); +#else + if ( xin_modal_win != XI_NULL_WINDOW + && ep->type == E_FOCUS + && ep->v.active + && xin_modal_win != ( XinWindow ) win ) + XinWindowFrontSet( xin_modal_win ); +#endif + if ( xin_modal_win != XI_NULL_WINDOW + && ( XinWindow ) win != xin_modal_win + && XinWindowParentGet( ( XinWindow ) win ) != xin_modal_win && ep->type != E_UPDATE + && ep->type != E_TIMER ) + return 0L; +#endif + /* Autoclose behavior */ + if ( ( ( ep->type == E_FOCUS && !ep->v.active ) || + ( ep->type == E_CHAR && ep->v.chr.ch == '\033' ) ) && + ( WINDOW ) xin_autoclose_win == win ) + { + MEMCLEAR( fake_event ); + fake_event.type = E_CLOSE; + ep = &fake_event; + } + + + /* Font event */ + if ( ep->type == E_COMMAND && ep->v.cmd.tag == XI_MENU_FONT_SELECT ) + { + XVT_FNTID font_id; + + font_id = xvt_dwin_get_font( win ); + xvt_dm_post_font_sel( win, font_id, NULL, 0L ); + xvt_font_destroy( font_id ); + return 0L; + } + + /* Help event - the user pressed F1 */ + if (ep->type == E_HELP) + { /* XVT sends the event to the task window. We want to redirect it to the focus window. */ + win = (WINDOW)XinWindowFocusGet(); + } + + ehlt = find_window_info( win ); + if ( ehlt != NULL ) + { + XinEvent event; + + MEMCLEAR( event ); + + if ( ConvertEvent( ep, &event ) ) + { + EVENT* old_cur_event = cur_xvt_event; + + cur_xvt_event = ep; + ( *ehlt->event_handler ) ( ( XinWindow ) win, &event ); + cur_xvt_event = old_cur_event; + if ( event.type == XinEventFont ) + XinFontDestroy( event.v.font.font ); + } + if ( ep->type == E_DESTROY ) + deregister_window( win ); + } + return 0L; +} + +/*START*/ +/* +this function creates a window or a scroll bar using the information in 'Def'. +*/ +XinWindow +XinWindowCreate( XinWindowDef * Def ) +{ +/*END*/ + WINDOW parent; + long flags; + WIN_TYPE win_type; + XinWindow win; + +#if XIWS == XIWS_WIN || XIWS == XIWS_PM + int old_icon_rid; + +#endif + + switch ( Def->type ) + { + case XinWindowTypeDocument: + if ( Def->parent == XI_NULL_WINDOW ) + parent = TASK_WIN; + else + parent = ( WINDOW ) Def->parent; + flags = ( Def->close_button ? WSF_CLOSE : 0 ) | + ( Def->horizontal_scroll_bar ? WSF_HSCROLL : 0 ) | + ( Def->vertical_scroll_bar ? WSF_VSCROLL : 0 ) | + ( Def->visible ? 0 : WSF_INVISIBLE ) | + ( Def->enabled ? 0 : WSF_DISABLED ) | + ( Def->maximized ? WSF_MAXIMIZED : 0 ) | + ( Def->iconizable ? WSF_ICONIZABLE : 0 ) | + ( Def->iconized ? WSF_ICONIZED : 0 ); +#if XVT_CHECK_VERSION(4, 50, 0) + if ( Def->mode == XinModalWait ) + { + win_type = W_MODAL; + if ( Def->close_button || Def->menu != NULL || Def->menu_bar_rid != 0 ) + XinError( 20301, XinSeverityFatal, 0L ); + } + else +#endif + switch ( Def->border_style ) + { + case XinBorderSizable: + win_type = W_DOC; + flags |= WSF_SIZE; + break; + case XinBorderSingle: + win_type = W_PLAIN; + flags &= ~WSF_CLOSE; + break; + case XinBorderDouble: + win_type = W_DBL; + flags &= ~WSF_CLOSE; + break; + case XinBorderNone: + win_type = W_NO_BORDER; + flags &= ~WSF_CLOSE; + break; + case XinBorderFixed: + win_type = W_DOC; + break; + default: + win_type = W_DOC; + flags |= WSF_SIZE; + break; + } + if ( Def->menu == NULL && Def->menu_bar_rid == 0 ) + flags |= WSF_NO_MENUBAR; + switch ( Def->mode ) + { + case XinModalWait: +/* This is too clever. If we are in DSC45, then XinModalWait falls through + to the XinModalReturn case. */ +#if XVT_CHECK_VERSION(4, 50, 0) + return XI_NULL_WINDOW; +#endif + xin_finish_create_def = Def; + /* don't break! We need to do the XinModalReturn stuff as well. */ + case XinModalReturn: + if ( parent == TASK_WIN ) + parent = SCREEN_WIN; + else + parent = TASK_WIN; + break; + default: + break; + } +#if XIWS == XIWS_WIN || XIWS == XIWS_PM + if ( Def->iconizable && Def->icon_rid != 0 ) + { + old_icon_rid = ( int ) xvt_vobj_get_attr( NULL_WIN, + ATTR_WIN_PM_CLASS_ICON ); + xvt_vobj_set_attr( NULL_WIN, ATTR_WIN_PM_CLASS_ICON, Def->icon_rid ); + } + else + old_icon_rid = 0; +#endif + if ( Def->eh ) + xin_teh = Def->eh; + xin_finish_create_menu = Def->menu; +#if XIWS == XIWS_WIN + if (parent == SCREEN_WIN) + xvt_vobj_set_attr( 0, ATTR_WIN_POPUP_DETACHED, TRUE ); +#endif + win = ( XinWindow ) xvt_win_create( win_type, ( RCT * ) ( Def->p_rect ), + Def->title, Def->menu_bar_rid == 0 ? NULL_MENU_RID + : Def->menu_bar_rid, parent, flags, EM_ALL, + ( EVENT_HANDLER ) XinXvtEventHandler, Def->app_data ); +#if XIWS != XIWS_XM && XIWS != XIWS_WXGTK +#if XVT_CHECK_VERSION(4, 50, 0) + if ( Def->mode != XinModalWait && win != XI_NULL_WINDOW && + xvt_vobj_is_valid( ( WINDOW ) win ) ) + XinWindowFocusSet( win ); +#endif +#endif +#if XIWS == XIWS_WIN || XIWS == XIWS_PM + if ( old_icon_rid != 0 ) + xvt_vobj_set_attr( NULL_WIN, ATTR_WIN_PM_CLASS_ICON, old_icon_rid ); +#endif + assert4( win, "", 20090, "create_window returned NULL" ); +#if XVT_CHECK_VERSION(4, 50, 0) + if ( xvt_vobj_is_valid( ( WINDOW ) win ) ) + { /* We check because the window may have closed during its initial actions. */ +#endif + switch ( Def->mode ) + { + case XinModalReturn: + if ( Def->parent != XinWindowTaskGet( ) + && Def->parent != XinWindowScreenGet( ) ) + { /* Modal to parent only */ + WindowInfo *info = find_window_info( ( WINDOW ) win ); + + assert4( info != NULL, "", 20091, "Window information corrupt" ); + info->prev_modal = Def->parent; + XinWindowEnable( Def->parent, FALSE ); + } + else if ( xin_modal_win != XI_NULL_WINDOW ) + { /* Nested modal */ + WindowInfo *info = find_window_info( ( WINDOW ) win ); + + assert4( info != NULL, "", 20092, "Window information corrupt" ); + info->prev_modal = xin_modal_win; +#if XIWS == XIWS_WIN || XIWS == XIWS_PM || XIWS == XIWS_WM || XIWS == XIWS_MAC + XinWindowEnable( xin_modal_win, FALSE ); +#if XIWS == XIWS_MAC + XinWindowFrontSet( win ); +#endif +#endif + xin_modal_win = win; + } + else + { +#if XIWS == XIWS_WIN || XIWS == XIWS_PM + XinWindowEnable( XinWindowTaskGet( ), FALSE ); +#endif + xin_modal_win = win; +#if XIWS == XIWS_WM || XIWS == XIWS_MAC + { + SLIST win_list = xvt_scr_list_wins( ); + SLIST_ELT elt; + + for ( elt = xvt_slist_get_first( win_list ); elt != NULL; + elt = xvt_slist_get_next( win_list, elt ) ) + if ( ( XinWindow ) * xvt_slist_get_data( elt ) != xin_modal_win ) + XinWindowEnable( ( XinWindow ) * xvt_slist_get_data( elt ), FALSE ); + xvt_slist_destroy( win_list ); + } +#endif + } + break; + case XinModalAutoclose: + xin_autoclose_win = win; + break; + default: + break; + } +#if XVT_CHECK_VERSION(4, 50, 0) + } +#endif + return win; + case XinWindowTypeButton: + case XinWindowTypeRadioButton: + case XinWindowTypeCheckBox: + case XinWindowTypeHorizontalScrollBar: + case XinWindowTypeVerticalScrollBar: + { + WIN_DEF ctl_def; + +#if XVT_CHECK_VERSION(4, 50, 0) + XVT_COLOR_COMPONENT colors[8]; + +#endif + MEMCLEAR( ctl_def ); + switch ( Def->type ) + { + case XinWindowTypeButton: + ctl_def.wtype = WC_PUSHBUTTON; + break; + case XinWindowTypeRadioButton: + ctl_def.wtype = WC_RADIOBUTTON; + break; + case XinWindowTypeCheckBox: + ctl_def.wtype = WC_CHECKBOX; + break; + case XinWindowTypeHorizontalScrollBar: + Def->title = ""; + ctl_def.wtype = WC_HSCROLL; + break; + case XinWindowTypeVerticalScrollBar: + Def->title = ""; + ctl_def.wtype = WC_VSCROLL; + break; + default: + break; + } + flags = ( Def->visible ? 0 : CTL_FLAG_INVISIBLE ); + if ( !Def->enabled ) + flags |= CTL_FLAG_DISABLED; + ctl_def.rct = *( RCT * ) Def->p_rect; + ctl_def.text = Def->title; + ctl_def.v.ctl.ctrl_id = Def->control_id; + ctl_def.v.ctl.flags = flags; +#if XVT_CHECK_VERSION(4, 50, 0) + if ( Def->back_color ) + { + colors[0].type = XVT_COLOR_BLEND; + colors[0].color = Def->back_color; + colors[1].type = XVT_COLOR_NULL; + ctl_def.ctlcolors = colors; + } + if ( Def->font ) + ctl_def.v.ctl.font_id = Def->font->xvt_fntid; +#endif + return ( XinWindow ) xvt_ctl_create_def( &ctl_def, ( WINDOW ) Def->parent, 0L ); + } + default: + break; + } + return 0L; +/*START*/ +} + +/* This function is called when the create event for a window comes thru. + Other higher level stuff depends on this being done before any events + for the window are passed on. */ + +void +XinWindowCreateFinish( XinWindow win ) +{ +/*END*/ +#if XIWS == XIWS_PM + { + HWND hwnd = ( HWND ) xvt_vobj_get_attr( ( WINDOW ) win, ATTR_NATIVE_WINDOW ); + + if ( hwnd && old_pm_proc == NULL ) + old_pm_proc = WinSubclassWindow( hwnd, pm_proc ); + } +#endif + if ( xin_finish_create_menu != NULL ) + XinWindowMenuReplace( win, 0, xin_finish_create_menu ); + xvt_vobj_set_attr( NULL_WIN, ATTR_SUPPRESS_UPDATE_CHECK, ( long ) TRUE ); + + if ( xin_finish_create_def != NULL ) + { + XinWindowDef * Def = xin_finish_create_def; + if ( Def->parent != XinWindowTaskGet( ) + && Def->parent != XinWindowScreenGet( ) ) + { /* Modal to parent only */ + WindowInfo *info = find_window_info( ( WINDOW ) win ); + + assert4( info != NULL, "", 20091, "Window information corrupt" ); + info->prev_modal = Def->parent; + XinWindowEnable( Def->parent, FALSE ); + } + else if ( xin_modal_win != XI_NULL_WINDOW ) + { /* Nested modal */ + WindowInfo *info = find_window_info( ( WINDOW ) win ); + + assert4( info != NULL, "", 20092, "Window information corrupt" ); + info->prev_modal = xin_modal_win; +#if XIWS == XIWS_WIN || XIWS == XIWS_PM || XIWS == XIWS_WM || XIWS == XIWS_MAC + XinWindowEnable( xin_modal_win, FALSE ); +#if XIWS == XIWS_MAC + XinWindowFrontSet( win ); +#endif +#endif + xin_modal_win = win; + } + else + { +#if XIWS == XIWS_WIN || XIWS == XIWS_PM + XinWindowEnable( XinWindowTaskGet( ), FALSE ); +#endif + xin_modal_win = win; +#if XIWS == XIWS_WM || XIWS == XIWS_MAC + { + SLIST win_list = xvt_scr_list_wins( ); + SLIST_ELT elt; + + for ( elt = xvt_slist_get_first( win_list ); elt != NULL; + elt = xvt_slist_get_next( win_list, elt ) ) + if ( ( XinWindow ) * xvt_slist_get_data( elt ) != xin_modal_win ) + XinWindowEnable( ( XinWindow ) * xvt_slist_get_data( elt ), FALSE ); + xvt_slist_destroy( win_list ); + } +#endif + } + xin_finish_create_def = NULL; + } +/*START*/ +} + +/*END*/ +#if XIWS != XIWS_WM +static CURSOR +XinCursorToCURSOR( XinCursor Cursor ) +{ + switch ( Cursor ) + { +case XI_CURSOR_ARROW: + return CURSOR_ARROW; + case XI_CURSOR_IBEAM: + return CURSOR_IBEAM; + case XI_CURSOR_CROSS: + return CURSOR_CROCE; + } + return ( CURSOR ) Cursor; +} + +#endif + +/*START*/ +/* +this function sets the current cursor. the argument 'Cursor' can be: + XI_CURSOR_ARROW the ubiquitous arrow cursor + XI_CURSOR_IBEAM ibeam insertion point for edit controls + XI_CURSOR_CROSS a plus sign cursor (crosshairs) + XI_CURSOR_RESIZE horizontal resize + XI_CURSOR_HAND hand cursor (for moving columns in a list) + XI_CURSOR_VRESIZE vertical resize + +when the cursor is set, it remains in that state until the cursor is changed +by another call to this function. an exception is when XinCursorWait is called. +this changes the cursor to the waiting cursor (usually an hourglass), indicating that +the application +is busy. as soon as the event handler that is currently being processed returns, +then the cursor changes back to the current cursor (i.e. whatever cursor was +set the last time that XinWindowCursorSet was called) +*/ +void +XinWindowCursorSet( XinWindow win, XinCursor Cursor ) +{ +/*END*/ +#if XIWS != XIWS_WM + xvt_win_set_cursor( ( WINDOW ) win, XinCursorToCURSOR( Cursor ) ); +#else + NOREF( win ); + NOREF( Cursor ); +#endif +/*START*/ +} + +/* +this function destroys a previously created XinWindow. The XinWindow could either +be a top level window, or a scroll bar. +*/ +void +XinWindowDestroy( XinWindow win ) +{ +/*END*/ + WindowInfo *info = find_window_info( ( WINDOW ) win ); + + if ( win == xin_autoclose_win ) + xin_autoclose_win = XI_NULL_WINDOW; + if ( app_terminating ) + return; + if ( info != NULL ) + { + if ( win == xin_modal_win ) + { + xin_modal_win = info->prev_modal; + if ( xin_modal_win == XI_NULL_WINDOW ) + { /* Last modal window closed */ +#if XIWS == XIWS_WIN || XIWS == XIWS_PM + XinWindowEnable( XinWindowTaskGet( ), TRUE ); +#elif XIWS == XIWS_WM || XIWS == XIWS_MAC + { + SLIST win_list = xvt_scr_list_wins( ); + SLIST_ELT elt; + + for ( elt = xvt_slist_get_first( win_list ); elt != NULL; + elt = xvt_slist_get_next( win_list, elt ) ) + XinWindowEnable( ( XinWindow ) * xvt_slist_get_data( elt ), TRUE ); + xvt_slist_destroy( win_list ); + } +#endif + } + else + { /* Top nested window closed */ +#if XIWS == XIWS_WIN || XIWS == XIWS_PM || XIWS == XIWS_WM || XIWS == XIWS_MAC + XinWindowEnable( xin_modal_win, TRUE ); +#if XIWS != XIWS_WIN + XinWindowFrontSet( xin_modal_win ); +#endif +#endif + } + } + else if ( xin_modal_win != XI_NULL_WINDOW || info->prev_modal != XI_NULL_WINDOW ) + { /* Window is not top modal window */ + WindowInfo *cur_info; + XinWindow cur_win = xin_modal_win; + + if ( cur_win != XI_NULL_WINDOW ) + { + do + { + cur_info = find_window_info( ( WINDOW ) cur_win ); + assert4( cur_info != NULL, "", 20094, "Window information corrupt" ); + cur_win = cur_info->prev_modal; + } while ( cur_win != XI_NULL_WINDOW && cur_win != win ); + } + /* If cur_win is not null, then remove this window from the modal list. + * Otherwise, if there is a prev_modal link, the window is a parented + * modal. */ + if ( cur_win != XI_NULL_WINDOW ) + cur_info->prev_modal = info->prev_modal; + else if ( info->prev_modal != XI_NULL_WINDOW ) + XinWindowEnable( info->prev_modal, TRUE ); + } + } + xvt_vobj_destroy( ( WINDOW ) win ); +/*START*/ +} + +/*END*/ +static DRAW_MODE +DrawModeToMODE( XinDrawMode Mode ) +{ + switch ( Mode ) + { +case XinDrawModeCopy: + return M_COPY; + case XinDrawModeXor: + return M_XOR; + } + return M_COPY; +} + +static XinDrawMode +MODEToDrawMode( DRAW_MODE Mode ) +{ + switch ( Mode ) + { + case M_COPY: + return XinDrawModeCopy; + case M_XOR: + return XinDrawModeXor; + default: + break; + } + return XinDrawModeCopy; +} + +/*START*/ +/* +this function sets the drawing mode to XinDrawModeCopy or XinDrawModeXor. +see the discussion above on drawing modes. +*/ +void +XinWindowDrawModeSet( XinWindow win, XinDrawMode mode ) +{ +/*END*/ + xvt_dwin_set_draw_mode( ( WINDOW ) win, DrawModeToMODE( mode ) ); +/*START*/ +} + +/* +this function gets the currently set drawing tools. see the discussion above +on drawing tools for more information. +*/ +XinDrawTools * +XinWindowDrawToolsGet( XinWindow win, XinDrawTools * DrawTools ) +{ +/*END*/ + DRAW_CTOOLS ct; + + xvt_dwin_get_draw_ctools( ( WINDOW ) win, &ct ); + DrawTools->pen.fore_color = ct.pen.color; + DrawTools->pen.pattern = PATToPenPattern( ct.pen.pat ); + DrawTools->pen.width = ct.pen.width; + DrawTools->brush.fore_color = ct.brush.color; + DrawTools->brush.pattern = PATToBrushPattern( ct.brush.pat ); + DrawTools->draw_mode = MODEToDrawMode( ct.mode ); + DrawTools->opaque_text = ct.opaque_text; + DrawTools->text_fore_color = ct.fore_color; + DrawTools->text_back_color = ct.back_color; + return DrawTools; +/*START*/ +} + +/* +this function gets the currently drawing mode. see the discussion above +on drawing mode for more information. +*/ +XinDrawMode +XinWindowDrawModeGet( XinWindow win ) +{ +/*END*/ + DRAW_CTOOLS ct; + XinDrawMode mode; + + xvt_dwin_get_draw_ctools( ( WINDOW ) win, &ct ); + mode = MODEToDrawMode( ct.mode ); + return mode; +/*START*/ +} + +/* +this function gets an XinDrawTools that is a common configuration. the +common configuration consists of a black pen of width of 1 pixel, a solid +black brush, copy mode, foreground text color of black, background text color +of white, and non-opaque text. + +the implementation below is complete. +*/ +XinDrawTools * +XinWindowDrawToolsNormalGet( XinDrawTools * ct ) +{ + ct->pen.width = 1; + ct->pen.pattern = XinPenSolid; + ct->pen.fore_color = XI_COLOR_BLACK; + ct->brush.pattern = XinBrushSolid; + ct->brush.fore_color = XI_COLOR_BLACK; + ct->draw_mode = XinDrawModeCopy; + ct->text_fore_color = XI_COLOR_BLACK; + ct->text_back_color = XI_COLOR_WHITE; + ct->opaque_text = FALSE; + return ct; +} + +/* +this function sets the current drawing tools. the drawing tools may have been +defined by the user of Xin. or they may have been gotten from a call to +XinWindowDrawToolsNormalGet, or they may have been gotten from a call to +XinWindowDrawToolsGet. +*/ +void +XinWindowDrawToolsSet( XinWindow win, XinDrawTools * ct ) +{ +/*END*/ +#if XIWS == XIWS_WM + { + DRAW_CTOOLS xct; + + xct.pen.color = ct->pen.fore_color; + xi_fix_color( &xct.pen.color ); + xct.pen.pat = ct->pen.pattern; + xct.pen.width = ct->pen.width; + xct.pen.style = P_SOLID; + xct.brush.color = ct->brush.fore_color; + xi_fix_color( &xct.brush.color ); + xct.brush.pat = ct->brush.pattern; + xct.mode = DrawModeToMODE( ct->draw_mode ); + xct.opaque_text = ct->opaque_text; + xct.fore_color = ct->text_fore_color; + xi_fix_color( &xct.fore_color ); + xct.back_color = ct->text_back_color; + xi_fix_color( &xct.back_color ); + xvt_dwin_set_draw_ctools( ( WINDOW ) win, &xct ); + } +#else + { + DRAW_CTOOLS xct; + + xct.pen.color = ct->pen.fore_color; + xct.pen.pat = PenPatternToPAT( ct->pen.pattern ); + xct.pen.width = ct->pen.width; + switch ( ct->pen.pattern ) + { + case XinPenSolid: + case XinPenHollow: + xct.pen.style = P_SOLID; + break; + case XinPenDashed: + xct.pen.style = P_DASH; + break; + default: + break; + } + xct.brush.color = ct->brush.fore_color; + xct.brush.pat = BrushPatternToPAT( ct->brush.pattern ); + xct.mode = DrawModeToMODE( ct->draw_mode ); + xct.opaque_text = ct->opaque_text; + xct.fore_color = ct->text_fore_color; + xct.back_color = ct->text_back_color; + xvt_dwin_set_draw_ctools( ( WINDOW ) win, &xct ); + } +#endif +/*START*/ +} + +/* +this function draws an ellipse in the specified window, following the state of +clipping, pens, brushes, and copy mode. see the drawing discussion above for +more details. +*/ +void +XinWindowEllipseDraw( XinWindow Win, XinRect * rctp ) +{ +/*END*/ + RCT r; + + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->bottom; + xvt_dwin_draw_oval( ( WINDOW ) Win, &r ); +/*START*/ +} + +/* +this function sets the enabled state of a window. see the discussion on +windows above for information on enabling and disabling windows. +*/ +void +XinWindowEnable( XinWindow Win, BOOLEAN Enable ) +{ +/*END*/ + xvt_vobj_set_enabled( ( WINDOW ) Win, Enable ); +/*START*/ +} + +/* +this function causes an XinEventUser to be sent to the window. for the +MFC implementation, this function simply declares an XinEvent, clears the +event, sets the 'id' and 'ptr' fields in the XinEvent, and calls the +event handler for the window. +*/ +void +XinWindowEventUserSend( XinWindow win, long id, void *ptr ) +{ +/*END*/ + EVENT event; + + event.type = E_USER; + event.v.user.id = id; + event.v.user.ptr = ptr; + XinXvtEventHandler( ( WINDOW ) win, &event ); +/*START*/ +} + +/* +this function maps a font to a previously created XinWindow. +*/ +void +XinWindowFontMap( XinWindow Win, XinFont * Font ) +{ +/*END*/ + xvt_font_map( Font->xvt_fntid, ( WINDOW ) Win ); +/*START*/ +} + +void +XinFontUnmap( XinFont * font ) +{ + xvt_font_unmap( font->xvt_fntid ); +} + +/* +this function returns the window with the current keyboard focus. +normally, this is the top window. +*/ +XinWindow +XinWindowFocusGet( void ) +{ +/*END*/ + return ( XinWindow ) xvt_scr_get_focus_topwin( ); +/*START*/ +} + +/* +this function makes the specified window have the keyboard focus. it +doesn't change which window is on top. +*/ +void +XinWindowFocusSet( XinWindow Win ) +{ +/*END*/ + xvt_scr_set_focus_vobj( ( WINDOW ) Win ); +/*START*/ +} + +/* +this function makes the specified window be the top window. +*/ +void +XinWindowFrontSet( XinWindow Win ) +{ +/*END*/ + xvt_vobj_raise( ( WINDOW ) Win ); +/*START*/ +} + +void +XinWindowHotkeySet( XinWindow win, char ch ) +{ + NOREF( win ); + NOREF( ch ); +} + +/* +this function draws the icon specifed by the resource id in 'IconRid' in the +specified window. the MFC implementation ignores the fore_color and back_color +because the icons have colors. fore_color and back_color are only used +on GUIs where icons might be black and white, such as X/Motif. 'x' and +'y' specify the position where the icon is drawn. +*/ +void +XinWindowIconDraw( XinWindow Win, int x, int y, int IconRid, + XinColor fore_color, XinColor back_color ) +{ +/*END*/ +#if XIWS == XIWS_WM + NOREF( Win ); + NOREF( x ); + NOREF( y ); + NOREF( IconRid ); + NOREF( fore_color ); + NOREF( back_color ); +#else +#if XIWS == XIWS_XM || XIWS == XIWS_MAC || XIWS == XIWS_WXGTK + if ( fore_color ) + xvt_dwin_set_fore_color( ( WINDOW ) Win, fore_color ); + if ( back_color ) + xvt_dwin_set_back_color( ( WINDOW ) Win, back_color ); +#else + NOREF( fore_color ); + NOREF( back_color ); +#endif +/*** Hack for PM only 08/96 XVT 4.02 */ +#if XIWS == XIWS_PM + { + XinDrawTools new_ctools; + XinDrawTools save_ctools; + + new_ctools.pen.width = 1; + new_ctools.pen.fore_color = XI_COLOR_BLACK; + new_ctools.pen.pattern = XinPenSolid; + + new_ctools.brush.pattern = XinBrushSolid; + new_ctools.brush.fore_color = XI_COLOR_BLACK; + + new_ctools.draw_mode = XinDrawModeCopy; + + new_ctools.opaque_text = TRUE; + new_ctools.text_fore_color = fore_color; + new_ctools.text_back_color = back_color; + + XinWindowDrawToolsGet( Win, &save_ctools ); + XinWindowDrawToolsSet( Win, &new_ctools ); + { + RCT r; + + r.top = y; + r.left = x; + r.bottom = y + 1; + r.right = x + 1; + xvt_dwin_draw_rect( ( WINDOW ) Win, &r ); + } + XinWindowDrawToolsSet( Win, &save_ctools ); + } +#endif + xvt_dwin_draw_icon( ( WINDOW ) Win, x, y, IconRid ); +#endif +/*START*/ +} + +/*END*/ +static XinPoint save_move_to; + +/*START*/ +/* +this function draws a line from the point previously passed to XinWindowLineMoveTo +or the point in the last XinWindowLineDraw call +to the point passed to this function. this function obeys the state in the +draw tools (or the functions that set the individual components of drawing tools). +the state that affects line drawing is the draw mode and pen. +*/ +void +XinWindowLineDraw( XinWindow Win, XinPoint * pnt ) +{ +/*END*/ + PNT mtp, + mpnt; + + mtp.v = save_move_to.v; + mtp.h = save_move_to.h; + mpnt.v = pnt->v; + mpnt.h = pnt->h; + + if ( mtp.v != mpnt.v && mtp.h != mpnt.h ) + { + if ( mtp.h > mpnt.h ) + { + PNT tpnt; + + tpnt = mtp; + mtp = mpnt; + mpnt = tpnt; + } +#if XIWS == XIWS_PM + if ( mtp.v > mpnt.v ) + { + mtp.v--; + mpnt.h--; + } + else + { + mpnt.v--; + mpnt.h--; + } +#elif XIWS == XIWS_MAC + if ( mtp.v > mpnt.v ) + { + mpnt.h--; + mpnt.v++; + } + else + { + mtp.v++; + mpnt.h--; + } + mtp.v--; + mpnt.v--; +#elif XIWS == XIWS_WIN + if ( mtp.v > mpnt.v ) + { + mpnt.v--; + mtp.v--; + } +#elif XIWS == XIWS_XM || XIWS == XIWS_WXGTK + if ( mtp.v > mpnt.v ) + { + mpnt.h--; + mtp.v--; + } + else + { + mpnt.h--; + mpnt.v--; + } +#endif + } + else + { +#if XIWS == XIWS_MAC || XIWS == XIWS_XM || XIWS == XIWS_PM || XIWS == XIWS_WXGTK + if ( mtp.v == mpnt.v ) + --mpnt.h; + if ( mtp.h == mpnt.h ) + --mpnt.v; +#endif + } + xvt_dwin_draw_set_pos( ( WINDOW ) Win, mtp ); + xvt_dwin_draw_line( ( WINDOW ) Win, mpnt ); + save_move_to = *pnt; +/*START*/ +} + +/* +the user of Xin calls this function just prior to calling XinWindowLineDraw, +to specify the starting point for drawing a line. +*/ +void +XinWindowLineMoveTo( XinWindow Win, XinPoint * pnt ) +{ +/*END*/ + NOREF( Win ); + save_move_to = *pnt; +/*START*/ +} + +/* +if a menu item is checkable, then this function checks or un-checks the menu +item. +*/ +void +XinWindowMenuItemCheck( XinWindow Win, XinMenuTag Tag, BOOLEAN check ) +{ +/*END*/ + xvt_menu_set_item_checked( ( WINDOW ) Win, ( MENU_TAG ) Tag, check ); +/*START*/ +} + +/* +this function enables or disables a menu item. +*/ +void +XinWindowMenuItemEnable( XinWindow Win, XinMenuTag Tag, BOOLEAN Enable ) +{ +/*END*/ + xvt_menu_set_item_enabled( ( WINDOW ) Win, ( MENU_TAG ) Tag, Enable ); +/*START*/ +} + +/* +this function sets the checked font in the font selection dialog box to the +specified font. the next time that the font selection dialog is put up, +it will reflect the effects of the call to this function. +*/ +void +XinWindowMenuFontSet( XinWindow win, XinFont * fontp ) +{ +/*END*/ + xvt_menu_set_font_sel( ( WINDOW ) win, fontp->xvt_fntid ); +/*START*/ +} + +/*END*/ +static XinMenuItem *copy_menu_items( MENU_ITEM * items, int *p_nbr_children ); + +static char * +copy_xvt_menu_text( char *text, char mnemonic ) +{ + char *new_text; + char *from; + char *to; + int size = strlen( text ) + 2; + + new_text = to = XinMemoryAlloc( size ); + for ( from = text; *from != '\0'; ) + { + if ( *from == mnemonic ) + { + *to++ = '~'; + mnemonic = '\0'; + } + *to++ = *from++; + } + *to = '\0'; + return new_text; +} + +static void +copy_menu_item( XinMenuItem * new_item, MENU_ITEM * item ) +{ + new_item->tag = item->tag; + if ( item->text == NULL ) + new_item->text = NULL; + else + new_item->text = copy_xvt_menu_text( item->text, ( char ) item->mkey ); + new_item->enabled = item->enabled; + new_item->checked = item->checked; + new_item->checkable = item->checkable; + new_item->separator = item->separator; + if ( item->child == 0 ) + { + new_item->nbr_children = 0; + new_item->children = NULL; + } + else + new_item->children = copy_menu_items( item->child, + &new_item->nbr_children ); +} + +static XinMenuItem * +copy_menu_items( MENU_ITEM * items, int *p_nbr_children ) +{ + MENU_ITEM *item; + XinMenuItem *new_items; + XinMenuItem *new_item; + int count; + + count = 0; + for ( item = items; item->tag != 0; item++, count++ ) + ; + *p_nbr_children = count; + if ( count == 0 ) + return new_items = NULL; + else + { + new_items = XinMemoryAlloc( count * sizeof( XinMenuItem ) ); + for ( item = items, new_item = new_items; item->tag != 0; + item++, new_item++ ) + copy_menu_item( new_item, item ); + } + return new_items; +} + +static XinMenu * +make_menu( MENU_ITEM * items ) +{ + XinMenu *menu = XinMemoryAlloc( sizeof( XinMenu ) ); + + menu->items = copy_menu_items( items, &menu->nbr_items ); + return menu; +} + +static MENU_ITEM *make_xvt_menu( int nbr_items, XinMenuItem * items ); + +static void +xvt_menu_set_text( MENU_ITEM * item, char *text ) +{ + char *from; + char *to; + int size = strlen( text ) + 1; + + item->text = xvt_mem_alloc( size ); + for ( from = text, to = item->text; *from != '\0'; ) + { + if ( *from == '~' ) + { + from++; + item->mkey = *from; + } + else + *to++ = *from++; + } + *to = '\0'; +} + +static void +copy_item_to_xvt( MENU_ITEM * new_item, XinMenuItem * item ) +{ + if ( item->text == NULL ) + new_item->text = NULL; + else + xvt_menu_set_text( new_item, item->text ); + new_item->tag = item->tag; + new_item->enabled = item->enabled; + new_item->checked = item->checked; + new_item->checkable = item->checkable; + new_item->separator = item->separator; + if ( item->nbr_children == 0 ) + new_item->child = NULL; + else + new_item->child = make_xvt_menu( item->nbr_children, item->children ); +} + +static MENU_ITEM * +make_xvt_menu( int nbr_items, XinMenuItem * items ) +{ + MENU_ITEM *xvt_menu; + XinMenuItem *item; + MENU_ITEM *new_item; + int num; + + if ( nbr_items == 0 ) + return NULL; + xvt_menu = ( MENU_ITEM * ) xvt_mem_zalloc( ( nbr_items + 1 ) + * sizeof( MENU_ITEM ) ); + for ( num = 0, item = items, new_item = xvt_menu; num < nbr_items; + item++, new_item++, num++ ) + copy_item_to_xvt( new_item, item ); + return xvt_menu; +} + +static MENU_ITEM * +find_item( MENU_ITEM * tree, XinMenuTag tag ) +{ + MENU_ITEM *item; + + for ( item = tree; item->tag != 0; item++ ) + { + if ( item->tag == tag ) + return item; + if ( item->child != NULL ) + { + MENU_ITEM *sub_item = find_item( item->child, tag ); + + if ( sub_item != NULL ) + return sub_item; + } + } + return NULL; +} + +/*START*/ +/* +this function returns an XinMenu tree for an existing menu. if tag == 0 then +this function returns the entire menu hierarchy. if tag != 0, then this function +returns the XinMenu tree from the menu item with the specified tag through to +the tips of the branches. + +the returned XinMenu has been allocated on the heap, and will need to be freed +by a call to XinMenuDelete. +*/ +XinMenu * +XinWindowMenuGet( XinWindow win, XinMenuTag tag ) +{ +/*END*/ + MENU_ITEM *item; + XinMenu *menu; + MENU_ITEM *tree = xvt_menu_get_tree( ( WINDOW ) win ); + + if ( tag == 0 ) + menu = make_menu( tree ); + else + { + item = find_item( tree, tag ); + if ( item->child == 0 ) + menu = NULL; + else + menu = make_menu( item->child ); + } + xvt_res_free_menu_tree( tree ); + return menu; +/*START*/ +} + +/* +this function returns the checked state of a checkable menu item. +*/ +BOOLEAN +XinWindowMenuItemIsChecked( XinWindow win, XinMenuTag tag ) +{ +/*END*/ + BOOLEAN checked; + XinMenuItem *item = XinWindowMenuItemGet( win, tag ); + + if ( item == 0 ) + return FALSE; + checked = item->checked; + XinMenuItemFree( item ); + return checked; +/*START*/ +} + +/* +this function returns the enabled state of a menu item. +*/ +BOOLEAN +XinWindowMenuItemIsEnabled( XinWindow win, XinMenuTag tag ) +{ +/*END*/ + BOOLEAN enabled; + XinMenuItem *item = XinWindowMenuItemGet( win, tag ); + + if ( item == 0 ) + return FALSE; + enabled = item->enabled; + XinMenuItemFree( item ); + return enabled; +/*START*/ +} + +/* +this function replaces a single menu item with the specified tag. +*/ +void +XinWindowMenuItemReplace( XinWindow win, XinMenuTag tag, XinMenuItem * item ) +{ +/*END*/ + MENU_ITEM *old_item; + MENU_ITEM *tree = xvt_menu_get_tree( ( WINDOW ) win ); + + old_item = find_item( tree, tag ); + if ( item != NULL ) + { + copy_item_to_xvt( old_item, item ); + } + xvt_res_free_menu_tree( tree ); +/*START*/ +} + +/* +this function retrieves a menu item. it allocates the XinMenuItem. the +allocated XinMenuItem should be placed in a menu tree, or else explicitely +freed, otherwise, a memory leak will occur. +*/ +XinMenuItem * +XinWindowMenuItemGet( XinWindow win, XinMenuTag tag ) +{ +/*END*/ + MENU_ITEM *item; + XinMenuItem *new_item; + MENU_ITEM *tree = xvt_menu_get_tree( ( WINDOW ) win ); + + item = find_item( tree, tag ); + if ( item == NULL ) + new_item = NULL; + else + { + new_item = XinMemoryAlloc( sizeof( XinMenuItem ) ); + copy_menu_item( new_item, item ); + } + xvt_res_free_menu_tree( tree ); + return new_item; +/*START*/ +} + +/* +this function replaces an existing menu tree with the specified menu tree. +if tag == 0, then this function replaces the entire menu tree for the window. +if tag != 0, then this function replaces just the branch of the tree, starting +at the menu item with the specified tag. +*/ +void +XinWindowMenuReplace( XinWindow win, XinMenuTag tag, XinMenu * menu ) +{ +/*END*/ + MENU_ITEM *item; + MENU_ITEM *tree; + + if ( tag == 0 ) + { + tree = make_xvt_menu( menu->nbr_items, menu->items ); + if ( tree == NULL ) + return; + xvt_menu_set_tree( ( WINDOW ) win, tree ); + } + else + { + tree = xvt_menu_get_tree( ( WINDOW ) win ); + item = find_item( tree, tag ); + if ( item != NULL ) + { + if ( item->child != NULL ) + xvt_res_free_menu_tree( item->child ); + if ( menu->nbr_items == 0 ) + item->child = NULL; + else + item->child = make_xvt_menu( menu->nbr_items, menu->items ); + xvt_menu_set_tree( ( WINDOW ) win, tree ); + } + } + if ( tree != NULL ) + xvt_res_free_menu_tree( tree ); +/*START*/ +} + +/* +gets the text of the specified menu item. +*/ +char * +XinWindowMenuItemTextGet( XinWindow win, XinMenuTag tag ) +{ +/*END*/ + XinMenuItem *item = XinWindowMenuItemGet( win, tag ); + + XinInitBuffer( ); + if ( item == 0 ) + return NULL; + if ( item->text == NULL ) + xin_buffer[0] = '\0'; + else + strcpy( xin_buffer, item->text ); + XinMenuItemFree( item ); + return xin_buffer; +/*START*/ +} + +/* +sets the text of the specified menu item. +*/ +void +XinWindowMenuItemTextSet( XinWindow win, XinMenuTag tag, char *text ) +{ +/*END*/ + xvt_menu_set_item_title( ( WINDOW ) win, ( MENU_TAG ) tag, text ); +/*START*/ +} + +/* +this function traps the mouse to the specified window. see the discussion +above on mouse trapping. the argument 'continuous_mouse_moves' should be +implemented if not difficult to do. +*/ +void +XinWindowMouseTrap( XinWindow win, BOOLEAN continuous_mouse_moves ) +{ +/*END*/ + /* This is only handled under Motif. */ + NOREF( continuous_mouse_moves ); + + xvt_win_trap_pointer( ( WINDOW ) win ); +/*START*/ +} + +/* +this function releases a previously trapped mouse. +*/ +void +XinWindowMouseRelease( void ) +{ +/*END*/ + xvt_win_release_pointer( ); +/*START*/ +} + +/* +under the MFC port, this function will return the MFC object for the window. +this facilitates the module using Xin to write code that uses MFC directly if +necessary. +*/ +long +XinWindowNativeGet( XinWindow win ) +{ +/*END*/ + return xvt_vobj_get_attr( ( WINDOW ) win, ATTR_NATIVE_WINDOW ); +/*START*/ +} + +/* +this function forces all pending paint events to be generated. if certain +regions have been invalidated, and the module using Xin does not know that +all invalidated regions have received their respective paint events, then +the user of Xin can call this function. this is often done before calling +a scroll rectangular region function, because the scroll rectangular region +function uses the actual pixels in the window as the input for the bitblt. +*/ +void +XinWindowPaintForce( XinWindow Win ) +{ +/*END*/ + xvt_dwin_update( ( WINDOW ) Win ); +/*START*/ +} + +/* +when the user of Xin is processing an XinEventPaint, then it can call this +function to determine if a particular rectangle needs to be drawn. +*/ +BOOLEAN +XinWindowPaintNeeds( XinWindow Win, XinRect * rctp ) +{ +/*END*/ + return xvt_dwin_is_update_needed( ( WINDOW ) Win, ( RCT * ) rctp ); +/*START*/ +} + +/* +this function returns the parent of the specified window. for all top level +windows, the parent window is the task window. for scroll bars, the parent +window is the window that contains the scroll bar. Xin does not implement +child windows of top level windows. +*/ +XinWindow +XinWindowParentGet( XinWindow Win ) +{ +/*END*/ + return ( XinWindow ) xvt_vobj_get_parent( ( WINDOW ) Win ); +/*START*/ +} + +/* +this function sets the current pen for drawing lines. calls to XinWindowPenGet +and XinWindowDrawToolsGet will reflect the changes made through this call. +*/ +void +XinWindowPenSet( XinWindow win, XinPen * Pen ) +{ +/*END*/ + CPEN cpen; + + cpen.color = Pen->fore_color; + cpen.pat = PenPatternToPAT( Pen->pattern ); + cpen.width = Pen->width; + switch ( Pen->pattern ) + { + case XinPenDashed: + cpen.style = P_DASH; + break; + case XinPenDotted: + cpen.style = P_DOT; + break; + default: + cpen.style = P_SOLID; + break; + } +#if XIWS == XIWS_WM + xi_fix_color( &cpen.color ); +#endif + xvt_dwin_set_cpen( ( WINDOW ) win, &cpen ); +/*START*/ +} + +/* +this function draws a pie in the specified window, following the state of +clipping, pens, brushes, and copy mode. see the drawing discussion above for +more details. +*/ +void +XinWindowPieDraw( XinWindow Win, XinRect* rctp, XinPoint* start, XinPoint* stop ) +{ +/*END*/ + RCT r; + + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->bottom; + xvt_dwin_draw_pie( ( WINDOW ) Win, &r, start->h, start->v, stop->h, stop->v ); +/*START*/ +} + +/* +This function is used to translate points from one window coordinate system to +another. It does not have to work for scrollbars. The coordinate system of a +window is 0,0 in the upper-left corner of the client rectangle. The screen window +is 0,0 in the upper-left corner of the display. +*/ +void +XinWindowPointsTranslate( XinWindow FromWin, XinWindow ToWin, XinPoint * Pnts, int NbrPnts ) +{ +/*END*/ + xvt_vobj_translate_points( ( WINDOW ) FromWin, ( WINDOW ) ToWin, ( PNT * ) Pnts, NbrPnts ); +/*START*/ +} + +/* +this function draws a polygon in the specified window, following the state of +clipping, pens, brushes, and copy mode. see the drawing discussion above for +more details. +*/ +void +XinWindowPolygonDraw( XinWindow Win, XinPoint* points, int nbr_points ) +{ +/*END*/ + xvt_dwin_draw_polygon( ( WINDOW ) Win, (PNT*)points, nbr_points ); +/*START*/ +} + +/* +this function draws a rectangle in the specified window, following the state of +clipping, pens, brushes, and copy mode. see the drawing discussion above for +more details. +*/ +void +XinWindowRectDraw( XinWindow Win, XinRect * rctp ) +{ +/*END*/ + RCT r; + + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->bottom; +/* Hack for OS2 - rectangles won't draw if right or bottom equal + to SHRT_MAX 8/96 XVT 4.02 */ +#if XIWS == XIWS_PM + if ( r.right == SHRT_MAX ) + r.right = 9999; + if ( r.bottom == SHRT_MAX ) + r.bottom = 9999; +#endif + xvt_dwin_draw_rect( ( WINDOW ) Win, &r ); +/*START*/ +} + +/* +this function draws a dotted rectangle in the specified window (added by Guy). +*/ +void +XinWindowRoundRectDraw( XinWindow Win, XinRect * rctp, int rh, int rv ) +{ +/*END*/ + RCT r; + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->bottom; + xvt_dwin_draw_roundrect(( WINDOW ) Win, &r, rh, rv ); +/*START*/ +} + + +/* +this function draws a dotted rectangle in the specified window (added by Guy). +*/ +void +XinWindowDottedRectDraw( XinWindow Win, XinRect * rctp ) +{ +/*END*/ + RCT r; + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->bottom; + xvt_dwin_draw_dotted_rect( ( WINDOW ) Win, &r ); +/*START*/ +} + +static XinColor ModulateColour(XinColor col, int percent) +{ + int r,g,b,k = 0, inverse = 100; + if (percent > 0) + k = 255; + else + percent = -percent; + inverse = 100-percent; + r = ((k * percent) + (((col>>16)&0xFF) * inverse)) / 100; + g = ((k * percent) + (((col>> 8)&0xFF) * inverse)) / 100; + b = ((k * percent) + (((col>> 0)&0xFF) * inverse)) / 100; + return XinColorMake(r, g, b); +} + + +/* +this function draws a shaded rectangle in the specified window (added by Guy). +*/ +void +XinWindowShadedRectDraw( XinWindow Win, XinRect * rctp ) +{ +/*END*/ + XinDrawTools tools; + XinColor c1, c2, c0; + RCT r; + + XinWindowDrawToolsGet( Win, &tools ); + c0 = tools.brush.fore_color; + c1 = ModulateColour(tools.brush.fore_color, +20); + c2 = ModulateColour(tools.brush.fore_color, -20); + + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->top + 1*(rctp->bottom-rctp->top)/4; + xvt_dwin_draw_gradient_linear((WINDOW)Win, &r, c0, c0, 90); + + r.top = r.bottom; + r.bottom = rctp->bottom; + xvt_dwin_draw_gradient_linear((WINDOW)Win, &r, c1, c2, 90); + +/*START*/ +} + +/* +this function draws a check mark in the specified window (added by Guy). +*/ +void +XinWindowCheckMarkDraw( XinWindow Win, XinRect * rctp ) +{ +/*END*/ + RCT r; + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->bottom; + xvt_dwin_draw_checkmark((WINDOW)Win, &r); +/*START*/ +} + + +/* +this function fills in the rectangle passed in as a pointer 'Rctp' with the +coordinates of the client area of the specified window. The top and left +will always be 0. This function can be called for the screen window to +get the display size. +*/ +XinRect * +XinWindowRectGet( XinWindow Win, XinRect * Rctp ) +{ +/*END*/ + RCT r; + + xvt_vobj_get_client_rect( ( WINDOW ) Win, &r ); + Rctp->top = r.top; + Rctp->left = r.left; + Rctp->bottom = r.bottom; + Rctp->right = r.right; + return Rctp; +/*START*/ +} + +/* +this function introduces a paint event into the event queue. the area for which +a paint event will be generated is specified in the argument 'rctp'. +*/ +void +XinWindowRectInvalidate( XinWindow win, XinRect * rctp ) +{ +/*END*/ + RCT r; + + if ( rctp == NULL ) + { + xvt_dwin_invalidate_rect( ( WINDOW ) win, NULL ); +#ifdef COALESCE_UPDATES + { + WindowInfo *info = find_window_info( ( WINDOW ) win ); + + if ( info != NULL && info->coalesce.coalescing != 0 ) + info->coalesce.invalidated = FALSE; + } +#endif + return; + } + + r.left = rctp->left; + r.top = rctp->top; + r.right = rctp->right; + r.bottom = rctp->bottom; +#ifdef COALESCE_UPDATES + { + WindowInfo *info = find_window_info( ( WINDOW ) win ); + + if ( info != NULL && info->coalesce.coalescing != 0 ) + { + if ( info->coalesce.invalidated ) + XinRectEnclose( &info->coalesce.inv_rct, &info->coalesce.inv_rct, + rctp ); + else + info->coalesce.inv_rct = *rctp; + info->coalesce.invalidated = TRUE; + } + else + xvt_dwin_invalidate_rect( ( WINDOW ) win, &r ); + } +#else + xvt_dwin_invalidate_rect( ( WINDOW ) win, &r ); +#endif +/*START*/ +} + +/* +this function gets the rectangle of a window, including the border of the window. +The top and left values will reflect the windows position within its parent. +This function can be called for the screen window to get the display size. +*/ +XinRect * +XinWindowRectOuterGet( XinWindow Win, XinRect * Rctp ) +{ +/*END*/ + RCT r; + + xvt_vobj_get_outer_rect( ( WINDOW ) Win, &r ); + Rctp->top = r.top; + Rctp->left = r.left; + Rctp->bottom = r.bottom; + Rctp->right = r.right; + return Rctp; +/*START*/ +} + +/* +this function causes a rectangular region to be scrolled in a horizontal direction, +a vertical direction, or both. the window system will do a bitblt to move the pixels, +and invalidate the exposed region. only pixels inside the rectangle 'Rctp' are +affected. no pixels outside of the rectangle are affected. The clipping rectangle +should not affect this function. + +the paint event for the exposed region must come through recursively. +*/ +void +XinWindowRectScroll( XinWindow Win, XinRect * Rctp, int dh, int dv ) +{ +/*END*/ +#if XIWS == XIWS_WM + { /* Strange bug in CH needs clipping region set + * twice. */ + XinRect rct; + + rct = *Rctp; + rct.bottom += 24; + XinWindowClipSet( Win, &rct ); + XinWindowClipSet( Win, NULL ); + } +#endif +#if XIWS == XIWS_PM +/* Hack for OS2 - headings don't scroll if clip rect is not set + 8/96 XVT 4.02 */ + XinWindowClipSet( Win, Rctp ); +#endif +#if XIWS == XIWS_MAC + XinWindowClipSet( Win, NULL ); +#endif + xvt_dwin_scroll_rect( ( WINDOW ) Win, ( RCT * ) Rctp, dh, dv ); +/*START*/ +} + +/* +this function changes the size and/or position of the window as +specified by the rectangle, which specifies the outer rectangle. +*/ +void +XinWindowRectSet( XinWindow Win, XinRect * Rctp ) +{ +/*END*/ + xvt_vobj_move( ( WINDOW ) Win, ( RCT * ) Rctp ); +/*START*/ +} + +/* +this function has the identical functionality to XinWindowPointsTranslate, except +that it translates a rectangle instead of points. +*/ +void +XinWindowRectTranslate( XinWindow FromWin, XinWindow ToWin, XinRect * rect ) +{ +/*END*/ + xvt_vobj_translate_points( ( WINDOW ) FromWin, ( WINDOW ) ToWin, ( PNT * ) rect, 2 ); +/*START*/ +} + +/* +this function returns the screen window to the module using Xin. +*/ +XinWindow +XinWindowScreenGet( void ) +{ +/*END*/ + return ( XinWindow ) SCREEN_WIN; +/*START*/ +} + +/* +this function makes a window visible or invisible. +*/ +void +XinWindowShow( XinWindow Win, BOOLEAN Show ) +{ +/*END*/ + xvt_vobj_set_visible( ( WINDOW ) Win, Show ); +/*START*/ +} + +/* +this function returns the task window to the module using Xin. +*/ +XinWindow +XinWindowTaskGet( void ) +{ +/*END*/ + return ( XinWindow ) TASK_WIN; +/*START*/ +} + +/*END*/ +BOOLEAN xin_use_mdi_flag = TRUE; /* This is set in xiport2.c */ +/*START*/ + +/* +this function returns the window that is most appropriate to be +a drop-down-position window's parent. +*/ +XinWindow +XinWindowDropDownParentGet( XinWindow creating_win ) +{ +/*END*/ +#if XIWS == XIWS_WIN +#if 0 + if ( creating_win == xin_modal_win || xin_use_mdi_flag ) + return ( XinWindow ) SCREEN_WIN; /* Unless creating_win is modal, this + will have a title bar. Life sucks. */ + return ( XinWindow ) TASK_WIN; +#endif + return ( XinWindow ) SCREEN_WIN; +#else + return ( XinWindow ) TASK_WIN; +#endif +/*START*/ +} + +/* +this function sets or resets the opaque drawing mode for text drawing. +*/ +void +XinWindowTextOpaqueSet( XinWindow win, BOOLEAN opaque ) +{ +/*END*/ + DRAW_CTOOLS ct; + + xvt_dwin_get_draw_ctools( ( WINDOW ) win, &ct ); + ct.opaque_text = opaque; + xvt_dwin_set_draw_ctools( ( WINDOW ) win, &ct ); +/*START*/ +} + +/* +this function draws text in the specified window, using the specified font, +at the specified position. it uses the current fore_color, and back_color +if drawing in opaque mode. it obeys the current clipping region. +*/ +void +XinWindowTextDraw( XinWindow Win, XinFont * font, int x, int y, + char *buf, int len ) +{ +/*END*/ + if (buf && *buf && len) + { + xvt_dwin_set_font( ( WINDOW ) Win, font->xvt_fntid ); + xvt_dwin_draw_text( ( WINDOW ) Win, x, y, buf, len ); + } +/*START*/ +} + +/* +this function draws text in the specified window, using the specified font, +at the specified position and rotated by the specified amount. +it uses the current fore_color, and back_color if drawing in opaque mode. +it obeys the current clipping region. +*/ +void +XinWindowTextRotateDraw( XinWindow Win, XinFont * font, int x, int y, + int rotation, char *buf, int len ) +{ +/*END*/ + XinRect rect; + int leading, ascent, descent, height; + int num; + + if ( rotation == 0 ) + { + XinWindowTextDraw( Win, font, x, y, buf, len ); + return; + } else if ( rotation != 90 && rotation != 270 ) + return; + + xvt_dwin_set_font( (WINDOW)Win, font->xvt_fntid ); + xvt_font_map( font->xvt_fntid, (WINDOW)Win ); + xvt_font_get_metrics( font->xvt_fntid, &leading, &ascent, &descent ); + height = leading + ascent + descent; + if ( len == -1 ) + len = strlen( buf ); + if ( rotation == 90 ) + { + rect.top = y; + rect.bottom = y + len * height; + rect.left = x - ( ascent + leading ); + rect.right = x + descent; + } else + { + rect.top = y - len * height; + rect.bottom = y; + rect.left = x - descent; + rect.right = x + ascent + leading; + } + y = rect.top + leading + ascent; + for ( num = 0; num < len; num++, y += height, buf++ ) + { + int width = xvt_dwin_get_text_width( (WINDOW)Win, buf, 1 ); + if ( width < height ) + x = rect.left + ( height - width ) / 2; + else + x = rect.left; + xvt_dwin_draw_text( (WINDOW)Win, x, y, buf, 1 ); + } + xvt_dwin_draw_text( ( WINDOW ) Win, x, y, buf, len ); +/*START*/ +} + +/* +this function kills a timer identified by 'Timer_id'. +*/ +void +XinWindowTimerKill( XinWindow win, long Timer_id ) +{ +/*END*/ + NOREF( win ); + xvt_timer_destroy( Timer_id ); +/*START*/ +} + +/* +this function creates a timer that will generate events a specified number of +milliseconds apart. +*/ +long +XinWindowTimerSet( XinWindow Win, long Millisecs ) +{ +/*END*/ + return xvt_timer_create( ( WINDOW ) Win, Millisecs ); +/*START*/ +} + +/* +this function returns the title of the specified window. +*/ +char * +XinWindowTitleGet( XinWindow Win ) +{ +/*END*/ + static char title[256]; + if ( xvt_vobj_get_title( ( WINDOW ) Win, title, sizeof( title ) ) == NULL ) + title[0] = '\0'; + return title; +/*START*/ +} + +/* +this function sets the title of the specified window. +*/ +void +XinWindowTitleSet( XinWindow Win, const char *Title ) +{ +/*END*/ + xvt_vobj_set_title( ( WINDOW ) Win, Title ); +/*START*/ +} + +/*END*/ +static SCROLL_TYPE +convert_to_SCROLL_TYPE( XinScrollBarType type ) +{ + switch ( type ) + { + case XinScrollBarTypeHorizontal: + return HSCROLL; + case XinScrollBarTypeVertical: + return VSCROLL; + case XinScrollBarTypeEither: + return HVSCROLL; + } + return HSCROLL; +} + +/* +this function gets the current position of the scroll bar specified by +the argument 'Win'. +*/ +int +XinScrollBarPositionGet( XinWindow Win, XinScrollBarType Type ) +{ + return xvt_sbar_get_pos( ( WINDOW ) Win, convert_to_SCROLL_TYPE( Type ) ); +} + +/* +this function sets the current position of the scroll bar specified by +the argument 'Win'. +*/ +void +XinScrollBarPositionSet( XinWindow Win, XinScrollBarType Type, int Top ) +{ + if ( app_terminating ) + return; + xvt_sbar_set_pos( ( WINDOW ) Win, convert_to_SCROLL_TYPE( Type ), Top ); +} + +/* +this function gets the current proportion for a scrollbar +*/ +int +XinScrollBarProportionGet( XinWindow Win, XinScrollBarType Type ) +{ + return xvt_sbar_get_proportion( ( WINDOW ) Win, convert_to_SCROLL_TYPE( Type ) ); +} + +/* +this function gets the current range for a scrollbar +*/ +void +XinScrollBarRangeGet( XinWindow Win, XinScrollBarType Type, int *Rng1, int *Rng2 ) +{ + if ( app_terminating ) + return; + xvt_sbar_get_range( ( WINDOW ) Win, convert_to_SCROLL_TYPE( Type ), Rng1, Rng2 ); +} + +/* +this function sets the range (min_val, max_val), proportion, and position for +a scrollbar +*/ +void +XinScrollBarSet( XinWindow Win, XinScrollBarType Type, int min_val, int max_val, + int proportion, int pos ) +{ + WINDOW xvt_win = ( WINDOW ) Win; + SCROLL_TYPE scroll_type = convert_to_SCROLL_TYPE( Type ); + +#if XIWS == XIWS_XM + WINDOW parent_win = xvt_vobj_get_parent( xvt_win ); + + if ( proportion != 0 ) + { + if ( pos == min_val ) + pos = min_val + 1; + if ( pos == ( max_val - proportion ) ) + pos = max_val - proportion - 1; +#endif + xvt_sbar_set_range( xvt_win, scroll_type, min_val, max_val ); + xvt_sbar_set_proportion( xvt_win, scroll_type, proportion ); +#if XIWS == XIWS_WXGTK + if (pos >= 0) +#endif + xvt_sbar_set_pos( xvt_win, scroll_type, pos ); +#if XIWS == XIWS_XM + { + WINDOW focus_win = xvt_scr_get_focus_vobj(); + if ( parent_win && (focus_win == xvt_win) ) + xvt_scr_set_focus_vobj( parent_win ); + } + } +#endif +} + +/* +this function queries whether a particular format is available on the clipboard. +*/ +BOOLEAN +XinClipboardFormatAvail( XinClipboardFormat Format ) +{ +/*END*/ + switch ( Format ) + { + case XinClipboardFormatText: + return xvt_cb_has_format( CB_TEXT, NULL ); + case XinClipboardFormatBitmap: + return FALSE; + } + return FALSE; +/*START*/ +} + +/* +given a format, this function gets the contents of the clipboard. +*/ +void * +XinClipboardGet( XinClipboardFormat Format, long *size ) +{ +/*END*/ + char *ptr = NULL; + + if ( !xvt_cb_open( FALSE ) ) + return ptr; + switch ( Format ) + { + case XinClipboardFormatText: + { + void *cb_ptr; + + cb_ptr = xvt_cb_get_data( CB_TEXT, NULL, size ); + if ( cb_ptr != NULL && *size > 0 ) + { + ptr = XinMemoryAlloc( ( int ) ( *size + 1 ) ); + memcpy( ptr, cb_ptr, ( int ) *size ); + ptr[( int ) *size] = '\0'; + } + break; + } + case XinClipboardFormatBitmap: + ptr = NULL; + break; + } + xvt_cb_close( ); + return ptr; +/*START*/ +} + +/* +this function puts data on to the clipboard. the format of the +data is specified in the argument 'format'. +*/ +void +XinClipboardPut( XinClipboardFormat format, long size, void *data ) +{ +/*END*/ + CB_FORMAT xvt_format; + char *buf; + + if ( !xvt_cb_open( TRUE ) ) + return; + buf = xvt_cb_alloc_data( size + 1 ); + memcpy( buf, data, ( size_t ) size ); + buf[( int ) size] = '\0'; + switch ( format ) + { + case XinClipboardFormatText: + xvt_format = CB_TEXT; + buf = NULL; + break; + case XinClipboardFormatBitmap: + xvt_format = CB_PICT; + break; + default: + xvt_format = CB_APPL; + break; + } + xvt_cb_put_data( xvt_format, NULL, size + 1, ( PICTURE ) buf ); + xvt_cb_free_data( ); + xvt_cb_close( ); +/*START*/ +} + +/*END*/ +void +xi_terminate( void ) +{ + app_terminating = TRUE; + xvt_vobj_destroy( TASK_WIN ); +} + +/*START*/ +/* +when the application is terminated, it generates an XinEventQuit event. +during the XinEventQuit, the application can put up a dialog box if desired, +querying from the user whether it is ok to quit the application, and +possibly saving files. if it is ok for the application to quit, then +during processing of that event, the module using Xin should call +XinAppQuitOk. +*/ +void +XinAppQuitOk( void ) +{ +/*END*/ + xvt_app_allow_quit( ); +/*START*/ +} + +/* +this function terminates the application. it will cause an XinEventQuit +event to be generated. see XinAppQuitOk for more details. +*/ +void +XinAppTerminate( void ) +{ +/*END*/ + XinMemoryFree( xin_buffer ); + if (xin_family_names_initialized) + { + XinMemoryFree( xin_family_name_times ); + XinMemoryFree( xin_family_name_fixed ); + XinMemoryFree( xin_family_name_system ); + XinMemoryFree( xin_family_name_helvetica ); + } + app_terminating = TRUE; + xvt_vobj_destroy( TASK_WIN ); +/*START*/ +} + +/* +this function prints to a file named "DEBUG". if the file does not exist, +then this function does nothing. if the file exists, then the first time +that this function is called, it creates the debug file over top of the +existing one. thereafter, this function appends to the debug file. +The data written to the file must be flushed at the end of the function, +perhaps by closing the file. +*/ +void +XinDebugPrintf( char *format,... ) +{ +/*END*/ + va_list argptr; + + XinInitBuffer( ); + va_start( argptr, format ); + vsprintf( xin_buffer, format, argptr ); + va_end( argptr ); + xvt_debug_printf( "%s", xin_buffer ); +/*START*/ +} + +/* +this function forces any pending events to be sent to the application. +it typically is called during processing that will take more than one +or two seconds. +*/ +void +XinPendingEventsProcess( void ) +{ +/*END*/ + xvt_app_process_pending_events( ); +/*START*/ +} + +/* +this function makes a small noise. +*/ +void +XinBeep( void ) +{ +/*END*/ + xvt_scr_beep( ); +/*START*/ +} + +/* +this function takes separate red, green, and blue values and creates +one RGB value. + +the following implementation is complete. +*/ +XinColor +XinColorMake( int red, int green, int blue ) +{ + return ( red << 16 ) | ( green << 8 ) | blue; +} + +/* +this function compares a string to a pattern. the pattern can contain +wild cards (*, ?) returns TRUE if the pattern matches the string. +if 'case_sensitive' is true, then this function pays attention to the +case of the characters. +*/ +BOOLEAN +XinStringMatch( char *string, char *pattern, BOOLEAN case_sensitive ) +{ +/*END*/ + return xvt_str_match( string, pattern, case_sensitive ); +/*START*/ +} + +/* +this function changes the cursor to the wait cursor until the program +returns from processing the event during which this function was called. +*/ +void +XinCursorWait( ) +{ +/*END*/ + xvt_scr_set_busy_cursor( ); +/*START*/ +} + +/* +this function gets metrics of many things in the GUI. +*/ +long +XinMetricGet( XinMetricType type ) +{ + switch ( type ) + { + case XinMetricIconHeight: + return xvt_vobj_get_attr( NULL_WIN, ATTR_ICON_HEIGHT ); + case XinMetricIconWidth: + return xvt_vobj_get_attr( NULL_WIN, ATTR_ICON_WIDTH ); + case XinMetricHorizontalScrollBarHeight: + return xvt_vobj_get_attr( NULL_WIN, ATTR_CTL_HORZ_SBAR_HEIGHT ); + case XinMetricVerticalScrollBarWidth: + return xvt_vobj_get_attr( NULL_WIN, ATTR_CTL_VERT_SBAR_WIDTH ); + case XinMetricScreenHeight: + return xvt_vobj_get_attr( NULL_WIN, ATTR_SCREEN_HEIGHT ); + case XinMetricScreenWidth: + return xvt_vobj_get_attr( NULL_WIN, ATTR_SCREEN_WIDTH ); + case XinMetricSizableFrameHeight: + return xvt_vobj_get_attr( NULL_WIN, ATTR_DOCFRAME_HEIGHT ); + case XinMetricSizableFrameWidth: + return xvt_vobj_get_attr( NULL_WIN, ATTR_DOCFRAME_WIDTH ); + case XinMetricDoubleFrameHeight: + return xvt_vobj_get_attr( NULL_WIN, ATTR_DBLFRAME_HEIGHT ); + case XinMetricDoubleFrameWidth: + return xvt_vobj_get_attr( NULL_WIN, ATTR_DBLFRAME_WIDTH ); + case XinMetricFrameHeight: + return xvt_vobj_get_attr( NULL_WIN, ATTR_FRAME_HEIGHT ); + case XinMetricFrameWidth: + return xvt_vobj_get_attr( NULL_WIN, ATTR_FRAME_WIDTH ); + case XinMetricMenuHeight: + return xvt_vobj_get_attr( NULL_WIN, ATTR_MENU_HEIGHT ); + case XinMetricTitleHeight: + return xvt_vobj_get_attr( NULL_WIN, ATTR_TITLE_HEIGHT ); + case XinMetricVerticalStagger: + return xvt_vobj_get_attr( NULL_WIN, ATTR_DOC_STAGGER_VERT ); + case XinMetricHorizontalStagger: + return xvt_vobj_get_attr( NULL_WIN, ATTR_DOC_STAGGER_HORZ ); + case XinMetricScreenHRes: + return xvt_vobj_get_attr( NULL_WIN, ATTR_SCREEN_HRES ); + case XinMetricScreenVRes: + return xvt_vobj_get_attr( NULL_WIN, ATTR_SCREEN_VRES ); + } + return 0; +} + +/* +in some situations, we desire to coalesce invalidated regions. this is not +used for MFC. +*/ +void +XinCoalesceInvalidates( XinWindow win, BOOLEAN coalesce ) +{ +/*END*/ +#ifdef COALESCE_UPDATES + WindowInfo *info = find_window_info( ( WINDOW ) win ); + + if ( info != NULL ) + { + if ( coalesce ) + { + if ( info->coalesce.coalescing == 0 ) + info->coalesce.invalidated = FALSE; + ++info->coalesce.coalescing; + } + else + { + --info->coalesce.coalescing; + if ( info->coalesce.coalescing == 0 && info->coalesce.invalidated ) + XinWindowRectInvalidate( win, &info->coalesce.inv_rct ); + } + } +#else + NOREF( win ); + NOREF( coalesce ); +#endif +/*START*/ +} + +/*END*/ +void +XinXvtEventGet( void *xvte ) +{ + *( EVENT * ) xvte = *cur_xvt_event; +} + +#define UNDEFINED 1000 +char * +XinXvtEventTextGet( void *xvte ) +{ + int num; + static struct + { + int type; + char *desc; + } xvt_event_text[] = + { + { + E_CREATE, "E_CREATE" + }, + { + E_DESTROY, "E_DESTROY" + }, + { + E_FOCUS, "E_FOCUS" + }, + { + E_SIZE, "E_SIZE" + }, + { + E_UPDATE, "E_UPDATE" + }, + { + E_CLOSE, "E_CLOSE" + }, + { + E_MOUSE_DOWN, "E_MOUSE_DOWN" + }, + { + E_MOUSE_UP, "E_MOUSE_UP" + }, + { + E_MOUSE_MOVE, "E_MOUSE_MOVE" + }, + { + E_MOUSE_DBL, "E_MOUSE_DBL" + }, + { + E_CHAR, "E_CHAR" + }, + { + E_VSCROLL, "E_VSCROLL" + }, + { + E_HSCROLL, "E_HSCROLL" + }, + { + E_COMMAND, "E_COMMAND" + }, + { + E_FONT, "E_FONT" + }, + { + E_CONTROL, "E_CONTROL" + }, + { + E_TIMER, "E_TIMER" + }, + { + E_QUIT, "E_QUIT" + }, + { + E_HELP, "E_HELP" + }, + { + E_USER, "E_USER" + }, + { + UNDEFINED, "Unknown XVT Event" + } + }; + + for ( num = 0; xvt_event_text[num].type != ( ( EVENT * ) xvte )->type && + xvt_event_text[num].type != UNDEFINED; num++ ) + ; + return xvt_event_text[num].desc; +} + +/*START*/ +/* +this function returns whether a rectangle is empty or not. + +the following implementation is complete. +*/ +BOOLEAN +XinRectEmpty( XinRect * rect ) +{ + return ( rect->top >= rect->bottom && rect->left >= rect->right ); +} + +/* +this function determines the intersection between two mathmatical rectangles. + +the following implementation is complete. +*/ +XinRect * +XinRectIntersect( XinRect * result, XinRect * r1, XinRect * r2 ) +{ + XinRect rect; + + rect = *r1; + if ( r2->top > rect.top ) + rect.top = r2->top; + if ( r2->left > rect.left ) + rect.left = r2->left; + if ( r2->bottom < rect.bottom ) + rect.bottom = r2->bottom; + if ( r2->right < rect.right ) + rect.right = r2->right; + if ( rect.bottom < rect.top || rect.right < rect.left ) + { + rect.bottom = rect.top; + rect.right = rect.left; + } + *result = rect; + return result; +} + +/* +this function determines whether the specified point is contained in the +specified rectangle. + +the following implementation is complete. +*/ +BOOLEAN +XinRectPointContained( XinRect * rect, XinPoint * point ) +{ + return ( point->h >= rect->left && point->h <= rect->right + && point->v >= rect->top && point->v <= rect->bottom ); +} + +/* +get the enclosing rectangle of two other rectangles. +src1, src2 are the rects of interest. +dst is set to the enclosing rect and returned. +If is OK for dst to equal one of the sources. + +the following implementation is complete. +*/ +XinRect * +XinRectEnclose( XinRect * dst, XinRect * src1, XinRect * src2 ) +{ + XinRect rct; + + rct.top = min( src1->top, src2->top ); + rct.left = min( src1->left, src2->left ); + rct.bottom = max( src1->bottom, src2->bottom ); + rct.right = max( src1->right, src2->right ); + *dst = rct; + return ( dst ); +} + +/*END*/ +static void +menu_free_items( int nbr_items, XinMenuItem * items ) +{ + int num; + XinMenuItem *item; + + for ( num = 0, item = items; num < nbr_items; num++, item++ ) + { + if ( item->text != NULL ) + XinMemoryFree( item->text ); + if ( item->nbr_children != 0 ) + { + menu_free_items( item->nbr_children, item->children ); + XinMemoryFree( item->children ); + } + } +} + +static char * +copy_menu_text( char *text ) +{ + char *new_text; + int size = strlen( text ) + 1; + + new_text = XinMemoryAlloc( size ); + memcpy( new_text, text, size ); + return new_text; +} + +static XinMenuItem * +menu_clone_items( int nbr_items, XinMenuItem * items ) +{ + int num; + XinMenuItem *item; + XinMenuItem *new_items; + + new_items = XinMemoryAlloc( nbr_items * sizeof( XinMenuItem ) ); + memmove( new_items, items, nbr_items * sizeof( XinMenuItem ) ); + for ( num = 0, item = new_items; num < nbr_items; num++, item++ ) + { + if ( item->text != NULL ) + item->text = copy_menu_text( item->text ); + if ( item->nbr_children != 0 ) + item->children = menu_clone_items( item->nbr_children, item->children ); + } + return new_items; +} + +/*START*/ +/* +this function adds the specified menu item into a menu structure at the position +indicated by index. It does not change the menu for any window. + +it returns a pointer to the newly created menu item. +*/ +XinMenuItem * +XinMenuAdd( XinMenu * menu, int index, XinMenuItem * item ) +{ +/*END*/ + if ( index < 0 || index > menu->nbr_items ) + return NULL; + + if ( menu->nbr_items == 0 ) + { + menu->nbr_items = 1; + menu->items = XinMemoryAlloc( sizeof( XinMenuItem ) ); + } + else + { + menu->nbr_items++; + menu->items = XinMemoryRealloc( menu->items, menu->nbr_items + * sizeof( XinMenuItem ) ); + } + if ( index < menu->nbr_items - 1 ) + memmove( menu->items + index + 1, menu->items + index, + ( menu->nbr_items - index - 1 ) * sizeof( XinMenuItem ) ); + memmove( menu->items + index, item, sizeof( XinMenuItem ) ); + item = menu->items + index; + if ( item->text != NULL ) + item->text = copy_menu_text( item->text ); + if ( item->nbr_children != 0 ) + item->children = menu_clone_items( item->nbr_children, item->children ); + return item; +/*START*/ +} + +/* +this function creates an empty menu. subsequent to this, the module using Xin +will probably call XinMenuAdd. + +the following implementation is complete. +*/ +XinMenu * +XinMenuCreate( void ) +{ + XinMenu *menu = XinMemoryAlloc( sizeof( XinMenu ) ); + + menu->nbr_items = 0; + menu->items = NULL; + return menu; +} + +/* +this function deletes a menu item at a specified index in a menu structure. +It does not change the menu for any window. +*/ +BOOLEAN +XinMenuDelete( XinMenu * menu, int index ) +{ +/*END*/ + if ( index < 0 || index >= menu->nbr_items ) + return FALSE; + menu->nbr_items--; + if ( index < menu->nbr_items ) + memmove( menu->items + index, menu->items + index + 1, + ( menu->nbr_items - index ) * sizeof( XinMenuItem ) ); + return TRUE; +/*START*/ +} + +/* +this function allocates and duplicates a menu hierarchy +*/ +XinMenu * +XinMenuDuplicate( XinMenu * menu ) +{ +/*END*/ + XinMenu *new_menu = XinMemoryAlloc( sizeof( XinMenu ) ); + + new_menu->nbr_items = menu->nbr_items; + if ( menu->nbr_items != 0 ) + new_menu->items = menu_clone_items( menu->nbr_items, menu->items ); + else + new_menu->items = NULL; + return new_menu; +/*START*/ +} + +/* +this function frees a menu hierarchy +*/ +void +XinMenuFree( XinMenu * menu ) +{ +/*END*/ + if ( menu->items != NULL ) + { + menu_free_items( menu->nbr_items, menu->items ); + XinMemoryFree( menu->items ); + } + XinMemoryFree( menu ); +/*START*/ +} + +/* +this function adds the specified child menu item into a parent menu item. +It does not change the menu for any window. +*/ +XinMenuItem * +XinMenuItemAdd( XinMenuItem * parent, int index, XinMenuItem * child ) +{ +/*END*/ + if ( index < 0 || index > parent->nbr_children ) + return NULL; + + if ( parent->nbr_children == 0 ) + { + parent->nbr_children = 1; + parent->children = XinMemoryAlloc( sizeof( XinMenuItem ) ); + } + else + { + parent->nbr_children++; + parent->children = XinMemoryRealloc( parent->children, parent->nbr_children + * sizeof( XinMenuItem ) ); + } + if ( index < parent->nbr_children - 1 ) + memmove( parent->children + index + 1, parent->children + index, + ( parent->nbr_children - index - 1 ) * sizeof( XinMenuItem ) ); + memmove( parent->children + index, child, sizeof( XinMenuItem ) ); + child = parent->children + index; + if ( child->text != NULL ) + child->text = copy_menu_text( child->text ); + if ( child->nbr_children != 0 ) + child->children = menu_clone_items( child->nbr_children, child->children ); + return child; +/*START*/ +} + +/* +this function creates a menu item from a text string. +*/ +XinMenuItem * +XinMenuItemCreate( char *text ) +{ +/*END*/ + XinMenuItem *item = XinMemoryZeroAlloc( sizeof( XinMenuItem ) ); + + if ( text != NULL ) + item->text = copy_menu_text( text ); + return item; +/*START*/ +} + +/* +this function allocates and duplicates a menu item. +*/ +XinMenuItem * +XinMenuItemDuplicate( XinMenuItem * item ) +{ +/*END*/ + XinMenuItem *new_item = XinMemoryAlloc( sizeof( XinMenuItem ) ); + + memmove( new_item, item, sizeof( XinMenuItem ) ); + if ( item->nbr_children != 0 ) + new_item->children = menu_clone_items( item->nbr_children, + item->children ); + if ( item->text != NULL ) + new_item->text = copy_menu_text( item->text ); + return new_item; +/*START*/ +} + +/* +this function deletes a child menu item from a parent menu item. +It does not change the menu for any window. +*/ +BOOLEAN +XinMenuItemDelete( XinMenuItem * item, int index ) +{ +/*END*/ + if ( index < 0 || index >= item->nbr_children ) + return FALSE; + item->nbr_children--; + if ( index < item->nbr_children ) + memmove( item->children + index, item->children + index + 1, + ( item->nbr_children - index ) * sizeof( XinMenuItem ) ); + return TRUE; +/*START*/ +} + +/* +this function frees the memory for a menu item. +*/ +void +XinMenuItemFree( XinMenuItem * item ) +{ +/*END*/ + if ( item->nbr_children != 0 ) + { + menu_free_items( item->nbr_children, item->children ); + XinMemoryFree( item->children ); + } + if ( item->text != NULL ) + XinMemoryFree( item->text ); + XinMemoryFree( item ); +/*START*/ +} + +/* +this function sets the text on a menu item. +It does not change the menu for any window. +*/ +void +XinMenuItemTextSet( XinMenuItem * item, char *text ) +{ +/*END*/ + if ( item->text != NULL ) + XinMemoryFree( item->text ); + if ( text == NULL ) + item->text = NULL; + else + item->text = copy_menu_text( text ); +/*START*/ +} + +/*END*/ +#if XIWS == XIWS_XM +long +XinWindowGetWidget( XinWindow win ) +{ + return xvt_vobj_get_attr( ( WINDOW ) win, ATTR_X_WIDGET ); +} + +#endif + +/*START*/ +/* +this function returns whether the bold attribute is set for a font. +*/ +BOOLEAN +XinFontBoldGet( XinFont * font ) +{ + return font->bold; +} + +/* +this function sets the bold attribute for a font. +*/ +void +XinFontBoldSet( XinFont * font, BOOLEAN flag ) +{ +/*END*/ + unsigned long attrib; + + font->bold = flag; + attrib = xvt_font_get_style( font->xvt_fntid ); + if ( flag ) + attrib |= XVT_FS_BOLD; + else + attrib &= ~XVT_FS_BOLD; + xvt_font_set_style( font->xvt_fntid, attrib ); +/*START*/ +} + +/* +this function compares two fonts, and if they will have exactly the same +appearance, the function returns TRUE; if not, FALSE. +*/ +BOOLEAN +XinFontCompare( XinFont * f1, XinFont * f2 ) +{ +/*END*/ + char buf1[FONT_ATTR_SIZE]; + char buf2[FONT_ATTR_SIZE]; + + if ( f1 == f2 ) + return TRUE; + + if ( !f1->from_xvt_font && !f2->from_xvt_font ) + return ( f1->family == f2->family && f1->size == f2->size + && f1->bold == f2->bold && f1->italic == f2->italic ); + + /* XVT internal compare */ + + /* If both font have valid native descs, compare those */ + if ( xvt_font_get_native_desc( f1->xvt_fntid, buf1, FONT_ATTR_SIZE ) && + xvt_font_get_native_desc( f2->xvt_fntid, buf2, FONT_ATTR_SIZE ) ) + { + if ( *buf1 && *buf2 ) + return ( strncmp( buf1, buf2, FONT_ATTR_SIZE ) == 0 ); + } + + /* If one of the fonts lacks nd, compare portable attrs */ + if ( xvt_font_get_style( f1->xvt_fntid ) != xvt_font_get_style( f2->xvt_fntid ) ) + return FALSE; + + if ( xvt_font_get_size( f1->xvt_fntid ) != xvt_font_get_size( f2->xvt_fntid ) ) + return FALSE; + + if ( !xvt_font_get_family( f1->xvt_fntid, buf1, FONT_ATTR_SIZE ) ) + return FALSE; + if ( !xvt_font_get_family( f2->xvt_fntid, buf2, FONT_ATTR_SIZE ) ) + return FALSE; + + return ( strncmp( buf1, buf2, FONT_ATTR_SIZE ) == 0 ); +/*START*/ +} + +/* +this function creates a new font and initializes it with +a copy of the "Source" font, unless "Source" is NULL. +*/ +void +XinFontCopy( XinFont ** Dest, XinFont * Source ) +{ +/*END*/ + XinFont *new_font; + + if ( Source == NULL ) + *Dest = NULL; + else + { + new_font = XinMemoryAlloc( sizeof( XinFont ) ); + *Dest = new_font; + *new_font = *Source; + new_font->xvt_fntid = xvt_font_create( ); + xvt_font_copy( new_font->xvt_fntid, Source->xvt_fntid, + ( unsigned long ) XVT_FA_ALL ); + } +/*START*/ +} + +/* +this function allocates (creates) a font. after allocating the font, +the module using Xin may set the family, set the size, bold style, +italic style, and map the font to a window. +*/ +XinFont * +XinFontCreate( void ) +{ +/*END*/ + XinFont *xin_font; + + xin_font = XinMemoryZeroAlloc( sizeof( XinFont ) ); + xin_font->xvt_fntid = xvt_font_create( ); + return xin_font; +/*START*/ +} + +/* +this function destroys a font +*/ +void +XinFontDestroy( XinFont * font ) +{ +/*END*/ + xvt_font_destroy( font->xvt_fntid ); + XinMemoryFree( font ); +/*START*/ +} + +/* +this function returns the family for a font. If the font was selected +from a dialog, then XinFontFamilyOther may be returned. +*/ +XinFontFamily +XinFontFamilyGet( XinFont * font ) +{ + return font->family; +} + +/* +this function sets the family for a font. +*/ +void +XinFontFamilySet( XinFont * font, XinFontFamily family ) +{ +/*END*/ + font->family = family; + switch ( family ) + { + case XinFontFamilySystem: + xvt_font_set_family( font->xvt_fntid, XVT_FFN_SYSTEM ); + break; + case XinFontFamilyFixed: + xvt_font_set_family( font->xvt_fntid, XVT_FFN_COURIER ); + break; + case XinFontFamilyTimes: + xvt_font_set_family( font->xvt_fntid, XVT_FFN_TIMES ); + break; + case XinFontFamilyHelvetica: + xvt_font_set_family( font->xvt_fntid, XVT_FFN_HELVETICA ); + break; + default: + break; + } +/*START*/ +} + +/* +this function returns the mapped state of a font. +*/ +BOOLEAN +XinFontIsMapped( XinFont * font ) +{ +/*END*/ + return xvt_font_is_mapped( font->xvt_fntid ); +/*START*/ +} + +/* +this function returns the italic style state for a font. +*/ +BOOLEAN +XinFontItalicGet( XinFont * font ) +{ + return font->italic; +} + +/* +this function sets the italic style state for a font. +*/ +void +XinFontItalicSet( XinFont * font, BOOLEAN flag ) +{ +/*END*/ + unsigned long attrib; + + font->italic = flag; + attrib = xvt_font_get_style( font->xvt_fntid ); + if ( flag ) + attrib |= XVT_FS_ITALIC; + else + attrib &= ~XVT_FS_ITALIC; + xvt_font_set_style( font->xvt_fntid, attrib ); +/*START*/ +} + +/* +this function gets the vertical metrics for a font. the font must be mapped to +a window in order to call this function. +*/ +void +XinFontMetricsGet( XinFont * Font, int *Leading, int *Ascent, int *Descent ) +{ +/*END*/ + xvt_font_get_metrics( Font->xvt_fntid, Leading, Ascent, + Descent ); +/*START*/ +} + +/* +this function returns the point size for a font. +*/ +int +XinFontSizeGet( XinFont * Font ) +{ + return Font->size; +} + +/* +this function sets the point size for a font. +*/ +void +XinFontSizeSet( XinFont * Font, int size ) +{ +/*END*/ + Font->size = size; + xvt_font_set_size( Font->xvt_fntid, size ); +/*START*/ +} + +/* +this function gets the width in pixels for the specified text, based on the +specified font. the font must be mapped to a window. if 'len' is equal to +-1, then this function returns the pixel length of the entire string pointed +to by text. if 'len' is not equal to -1, then this function returns the pixel +length of the first 'len' characters of the string in 'text' +*/ +int +XinFontTextWidthGet( XinFont * font, char *text, int len ) +{ +/*END*/ + XVT_FNTID font_id = font->xvt_fntid; + WINDOW win; + + if ( !xvt_font_is_mapped( font_id ) ) + return 0; + win = xvt_font_get_win( font_id ); + xvt_dwin_set_font( win, font_id ); + return xvt_dwin_get_text_width( win, text, len ); +/*START*/ +} + +/* +this function destroys (frees) a bitmap. +*/ +void +XinBitmapDestroy( XinBitmap * bitmap ) +{ +/*END*/ + xvt_image_destroy( bitmap->image ); + XinMemoryFree( bitmap ); +/*START*/ +} + +/*END*/ +/*START*/ +/* +this function allocates, and reads a bitmap from the specified file. +*/ +XinBitmap * +XinBitmapRead( char *filename ) +{ +/*END*/ + XVT_IMAGE image; + XinBitmap *bitmap; + + if ( ( image = xvt_image_read( filename ) ) == NULL ) + return NULL; + bitmap = XinMemoryAlloc( sizeof( XinBitmap ) ); + bitmap->image = image; + if ( xin_palette == NULL ) + xin_palette = xvt_palet_create( XVT_PALETTE_USER, 0 ); + xvt_palet_add_colors_from_image( xin_palette, bitmap->image ); + xvt_vobj_set_palet( SCREEN_WIN, xin_palette ); + return bitmap; +/*START*/ +} + +/*START*/ +/* +this function allocates, and reads a bitmap from the resource file. +*/ +XinBitmap * +XinBitmapReadRes( short id) +{ +/*END*/ + XVT_IMAGE image; + XinBitmap *bitmap; + + if ( ( image = xvt_res_get_image( id ) ) == NULL ) + return NULL; + bitmap = XinMemoryAlloc( sizeof( XinBitmap ) ); + bitmap->image = image; + if ( xin_palette == NULL ) + xin_palette = xvt_palet_create( XVT_PALETTE_USER, 0 ); + xvt_palet_add_colors_from_image( xin_palette, bitmap->image ); + xvt_vobj_set_palet( SCREEN_WIN, xin_palette ); + return bitmap; +/*START*/ +} + +/* +this function returns the width and height of the +specified bitmap. +*/ +void +XinBitmapSizeGet( XinBitmap * bitmap, short *pw, short *ph ) +{ +/*END*/ + xvt_image_get_dimensions( bitmap->image, pw, ph ); +/*START*/ +} + +/* +this function returns the next band to be printed. see the discussion on printing +and banding above for more details. +*/ +XinRect * +XinPrintBandNext( void ) +{ +/*END*/ + return ( XinRect * ) xvt_print_get_next_band( ); +/*START*/ +} + +/* +this function is called when a page has been completely drawn. it causes the page +to be sent to the printer. +*/ +BOOLEAN +XinPrintPageEnd( XinPrintRecord * rec ) +{ +/*END*/ + return xvt_print_close_page( ( PRINT_RCD * ) rec ); +/*START*/ +} + +/* +this function is called when the module using Xin is about to print a page. +*/ +BOOLEAN +XinPrintPageStart( XinPrintRecord * rec ) +{ +/*END*/ + return xvt_print_open_page( ( PRINT_RCD * ) rec ); +/*START*/ +} + +/* +this function allocates and initializes a print record. after this function has +been called, then XinDialogPrinterSetup can be called, getting the user's +instructions on which printer to print the document, whether the document is printed +in landscape or portrait mode, etc. then, the filled in XinPrintRecord is passed +to XinPrintPageStart, XinPrintBandNext, and XinPrintPageEnd. +The returned print record will contain the default printer setup. +*/ +XinPrintRecord * +XinPrintRecordCreate( int *p_size ) +{ +/*END*/ + return ( XinPrintRecord * ) xvt_print_create( p_size ); +/*START*/ +} + +/* +this function frees up the memory and any resources +allocated for a print record. +*/ +void +XinPrintRecordDestroy( XinPrintRecord * rec ) +{ +/*END*/ + xvt_print_destroy( ( PRINT_RCD * ) rec ); +/*START*/ +} + +/* +this function returns whether a print record still contains valid information. an +example of invalid information is if the print record contains information on a +printer that is no longer attached to the computer. +*/ +BOOLEAN +XinPrintRecordValidate( XinPrintRecord * rec ) +{ +/*END*/ + return xvt_print_is_valid( ( PRINT_RCD * ) rec ); +/*START*/ +} + +/* +This function gets the height and width of the printer area in pixels (or dots), +and the vertical and horizontal resolution in pixels per inch. +*/ + +void +XinPrintRecordMetricsGet( XinPrintRecord * rec, long * height, long * width, + long * vres, long * hres ) +{ +/*END*/ + xvt_app_escape(XVT_ESC_GET_PRINTER_INFO, ( PRINT_RCD * ) rec, height, + width, vres, hres); +/*START*/ +} + +/* +on some implementations, it is necessary, or desirable, to start a +separate thread for printing. + +if threaded printing is implemented, then the thread should be started so that it +calls 'func' as soon as it starts. 'func' then does the actual printing. + +if threaded printing is not implemented, then this function simply calls 'func'. +*/ +BOOLEAN +XinPrintThreadStart( XinPrintHandler func, long app_data ) +{ +/*END*/ + return xvt_print_start_thread( func, app_data ); +/*START*/ +} + +/* +this function creates a print window. +*/ +XinWindow +XinPrintWindowCreate( XinPrintRecord * rec, char *title ) +{ +/*END*/ + return ( XinWindow ) xvt_print_create_win( ( PRINT_RCD * ) rec, title ); +/*START*/ +} + +/* +this function destroys a print window. +*/ +void +XinPrintWindowDestroy( XinWindow win ) +{ +/*END*/ + xvt_vobj_destroy( ( WINDOW ) win ); +/*START*/ +} + +/*END*/ +#if XIWS == XIWS_WIN +static char * +find_last_slash( char *str ) +{ + char *p = str + strlen( str ) - 1; + + if ( *str == '\0' ) + return NULL; + + while ( p != str ) + { + if ( *p == '\\' || *p == '/' ) + return p; + p--; + } + return NULL; +} + +static void +copy_leading_path( char *path, char *dest ) +{ + char *p = find_last_slash( path ); + + if ( p != NULL ) + { + int len = ( int ) ( p - path ); + + memmove( dest, path, len ); + dest[len] = '\0'; + } + else + *dest = '\0'; +} + +#endif + +/*START*/ +/* +This function returns the full directory path based on "full_name", which +may contain relative directory information. + +The implementation is complete. +*/ +BOOLEAN +XinDirectoryAbsoluteGet( char *full_name, XinDirectory * dir ) +{ +/*END*/ +#if XIWS == XIWS_WIN + XinDirectory current_dir; + + if ( isalpha( full_name[0] ) && full_name[1] == ':' ) + { /* Drive letter - find current directory for + * that drive */ + if ( full_name[2] == '\\' || full_name[2] == '/' ) + { /* Got full path name */ + copy_leading_path( full_name, ( char * ) dir ); + } + else + { /* Relative path for that drive. */ + XinDirectory save_dir; + char *p_dir = ( char * ) dir; + + if ( !XinDirectoryCurrentGet( &save_dir ) ) + return FALSE; + current_dir[0] = full_name[0]; + current_dir[1] = ':'; + current_dir[2] = '.'; + current_dir[3] = '\0'; + if ( !XinDirectoryCurrentSet( ¤t_dir ) ) + return FALSE; + if ( !XinDirectoryCurrentGet( ¤t_dir ) ) + { + XinDirectoryCurrentSet( &save_dir ); + return FALSE; + } + XinDirectoryCurrentSet( &save_dir ); + strcpy( p_dir, current_dir ); + p_dir += strlen( p_dir ); + *p_dir++ = '/'; + copy_leading_path( full_name + 2, p_dir ); + } + } + else + { + char *p_dir = ( char * ) dir; + + if ( !XinDirectoryCurrentGet( ¤t_dir ) ) + return FALSE; + if ( full_name[0] == '\\' || full_name[0] == '/' ) + { /* Got full path, but need drive */ + *p_dir++ = current_dir[0]; + *p_dir++ = ':'; + } + else + { /* Relative path */ + strcpy( p_dir, current_dir ); + p_dir += strlen( p_dir ); + *p_dir++ = '/'; + } + copy_leading_path( full_name, p_dir ); + } + { + /* copy_leading_path() can copy nothing, but we appended a '/' for it + * regardless. */ + char *p_dir = ( char * ) dir; + + p_dir += strlen( ( char * ) dir ) - 1; + if ( *p_dir == '/' ) + { + *p_dir = '\0'; + } + } +#elif XIWS == XIWS_MAC + char *p_dir; + + /* Leading colon means it is relative */ + if ( full_name[0] == ':' ) + { + if ( !XinDirectoryCurrentGet( dir ) ) + return FALSE; + p_dir = ( char * ) dir + strlen( ( char * ) dir ); + } + else + { + *( char * ) dir = '\0'; + p_dir = ( char * ) dir; + } + + /* Directory goes to last colon. */ + { + char *p = strrchr( full_name, ':' ); + + if ( p != NULL ) + { + int len = ( int ) ( p - full_name ); + + memmove( p_dir, full_name, len ); + p_dir[len] = '\0'; + } + } +#else + char *p_dir; + + /* Leading slash means it is absolute */ + if ( full_name[0] != '/' ) + { + if ( !XinDirectoryCurrentGet( dir ) ) + return FALSE; + p_dir = ( char * ) dir + strlen( ( char * ) dir ); + } + else + { + *( char * ) dir = '\0'; + p_dir = ( char * ) dir; + } + + /* Directory goes to last slash. */ + { + char *p = strrchr( full_name, '/' ); + + if ( p != NULL ) + { + int len = ( int ) ( p - full_name - 1 ); + + memmove( p_dir, full_name, len ); + p_dir[len] = '\0'; + } + } + +#endif + return TRUE; +/*START*/ +} + +/* +this function gets the current directory, and puts the result in an +XinDirectory. +*/ +BOOLEAN +XinDirectoryCurrentGet( XinDirectory * dir ) +{ +/*END*/ + return ( xvt_fsys_get_curr_dir( ( DIRECTORY * ) dir ) ); +/*START*/ +} + +/* +given an XinDirectory, this function sets the current directory. +*/ +BOOLEAN +XinDirectoryCurrentSet( XinDirectory * dir ) +{ +/*END*/ + return ( xvt_fsys_set_dir( ( DIRECTORY * ) dir ) ); +/*START*/ +} + +/* +given an XinFileListSpec, this function returns the list of files that match the +spec. +*/ +XinFileList * +XinFileListGet( XinFileListSpec * spec ) +{ +/*END*/ + static XinFileList files = {0, NULL}; + + int num; + SLIST slist; + SLIST_ELT element; + char **p_file_name; + + for ( num = 0; num < files.nbr_files; num++ ) + XinMemoryFree( files.file_names[num] ); + XinMemoryFree( files.file_names ); + files.nbr_files = 0; + files.file_names = NULL; + + if ( spec == NULL ) + return NULL; + + if ( ( slist = xvt_fsys_list_files( spec->dirs_only ? DIR_TYPE : spec->type, + spec->pattern, spec->include_dirs ) ) == NULL ) + return NULL; + files.nbr_files = xvt_slist_count( slist ); + files.file_names = XinMemoryAlloc( files.nbr_files * sizeof( char * ) ); + p_file_name = files.file_names; + for ( element = xvt_slist_get_first( slist ); element != NULL; + element = xvt_slist_get_next( slist, element ), p_file_name++ ) + { + long el_type; + char *text; + int len; + + text = xvt_slist_get( slist, element, &el_type ); + len = strlen( text ) + 1; + *p_file_name = XinMemoryAlloc( len ); + memmove( *p_file_name, text, len ); + } + xvt_slist_destroy( slist ); + + return &files; +/*START*/ +} + +static XinErrorHandler error_handler = NULL; + +/* +the module using Xin calls this function when it encounters an error, and needs +to take some action. there are two possible states of severity: +XinSeverityWarning and XinSeverityFatal. if the severity is XinSeverityWarning, +then this function puts up a error message box. if the severity is +XinSeverityFatal, then this function puts up an error message box, then terminates +the application. + +the module using Xin may set an error handler function by calling XinErrorHandlerSet. +if it does, then the new error handler is called. if the new error handler function +returns TRUE, then this function should terminate the application. + +the following implementation is complete. +*/ +void +XinError( int errcode, XinSeverity severity, long app_data ) +{ + BOOLEAN terminate = ( severity == XinSeverityFatal ); + + if ( error_handler != NULL ) + terminate = ( *error_handler ) ( errcode, severity, app_data ); + if ( terminate ) + XinAppTerminate( ); +} + +/* +this function gets and returns the Xin error handling function. +*/ +XinErrorHandler +XinErrorHandlerGet( void ) +{ + return error_handler; +} + +/* +this function sets the Xin error handling function. +*/ +void +XinErrorHandlerSet( XinErrorHandler handler ) +{ + error_handler = handler; +} + +/*END*/ + +void +XinInitBuffer( ) +{ + if ( xin_buffer == NULL ) + xin_buffer = XinMemoryAlloc( TEMP_BUFFER_SIZE ); +} + +void +XinIconSizeGet( int icon_rid, int *widthp, int *heightp ) +{ + NOREF( icon_rid ); + *widthp = 32; + *heightp = 32; +} + +#if XIWS == XIWS_WIN || XIWS == XIWS_PM + +static struct +{ + short xi_key; + short v_key; + BOOLEAN shift; +} + +vk_table[] = +{ +#if XIWS == XIWS_WIN + { + '\033', VK_ESCAPE, FALSE + }, + { + XI_KEY_BTAB, VK_BACK, TRUE, + }, + { + '\r', VK_RETURN, FALSE + }, + { + XI_KEY_PREV, VK_PRIOR, FALSE + }, + { + XI_KEY_NEXT, VK_NEXT, FALSE + }, +#endif +#if XIWS == XIWS_PM + { + '\033', VK_ESC, FALSE + }, + { + XI_KEY_BTAB, VK_BACKTAB, TRUE, + }, + { + '\r', VK_ENTER, FALSE + }, + { + XI_KEY_PREV, VK_PAGEUP, FALSE + }, + { + XI_KEY_NEXT, VK_PAGEDOWN, FALSE + }, +#endif + { + XI_KEY_DEL, VK_DELETE, FALSE + }, + { + '\t', VK_TAB, FALSE + }, + { + XI_KEY_END, VK_END, FALSE + }, + { + XI_KEY_HOME, VK_HOME, FALSE + }, + { + XI_KEY_LEFT, VK_LEFT, FALSE + }, + { + XI_KEY_UP, VK_UP, FALSE + }, + { + XI_KEY_RIGHT, VK_RIGHT, FALSE + }, + { + XI_KEY_DOWN, VK_DOWN, FALSE + }, + { + XI_KEY_F1, VK_F1, FALSE + }, + { + XI_KEY_F2, VK_F2, FALSE + }, + { + XI_KEY_F3, VK_F3, FALSE + }, + { + XI_KEY_F4, VK_F4, FALSE + }, + { + XI_KEY_F5, VK_F5, FALSE + }, + { + XI_KEY_F6, VK_F6, FALSE + }, + { + XI_KEY_F7, VK_F7, FALSE + }, + { + XI_KEY_F8, VK_F8, FALSE + }, + { + XI_KEY_F9, VK_F9, FALSE + }, + { + XI_KEY_F10, VK_F10, FALSE + }, + { + XI_KEY_F11, VK_F11, FALSE + }, + { + XI_KEY_F12, VK_F12, FALSE + }, + { + 0, 0, FALSE + } +}; + +#endif + +#if XIWS == XIWS_WIN +BOOLEAN XVT_CALLCONV1 +xin_xvt_win_raw_event_hook( MSG * pmsg, HWND * phwnd ) +{ + NOREF( phwnd ); + switch ( pmsg->message ) + { +case WM_SYSKEYDOWN: + { + WindowInfo *ehlt; + + ehlt = find_window_info_from_HWND( pmsg->hwnd ); + if ( ehlt != NULL ) + { + XinEvent event; + + MEMCLEAR( event ); + + event.type = XinEventCharacter; + event.v.character.ch = pmsg->wParam & 0xff; + event.v.character.shift = FALSE; + event.v.character.control = FALSE; + event.v.character.alt = TRUE; + event.v.character.consumed = FALSE; + if ( event.v.character.ch != 18 ) + { + int cnt; + + for ( cnt = 0; vk_table[cnt].xi_key != 0; ++cnt ) + { + if ( vk_table[cnt].v_key == event.v.character.ch ) + { + event.v.character.ch = vk_table[cnt].xi_key; + event.v.character.shift = vk_table[cnt].shift; + break; + } + } + { + EVENT* old_cur_event = cur_xvt_event; + EVENT xvt_event; + xvt_event.v.chr.ch = pmsg->wParam & 0xff; + xvt_event.v.chr.shift = FALSE; + xvt_event.v.chr.control = FALSE; + + cur_xvt_event = &xvt_event; + ( *ehlt->event_handler ) ( ( XinWindow ) ehlt->win, &event ); + cur_xvt_event = old_cur_event; + } +#if XVT_CHECK_VERSION(4, 50, 0) + return !event.v.character.consumed; +#else + return event.v.character.consumed; +#endif + } + } + break; + } + } +#if XVT_CHECK_VERSION(4, 50, 0) + return TRUE; +#else + return FALSE; +#endif +} + +#endif + +#if XIWS == XIWS_PM +BOOLEAN XVT_CALLCONV1 +xin_xvt_pm_raw_event_hook( QMSG * pmsg ) +{ + if ( pmsg->msg == ( ULONG ) WM_CHAR && + ( ( ( USHORT ) SHORT1FROMMP( pmsg->mp1 ) & KC_ALT ) != 0 ) ) + { + WindowInfo *ehlt; + + ehlt = find_window_info_from_HWND( pmsg->hwnd ); + if ( ehlt != NULL ) + { + XinEvent event; + + MEMCLEAR( event ); + + event.type = XinEventCharacter; + event.v.character.ch = LONGFROMMP( pmsg->mp2 ); + event.v.character.shift = FALSE; + event.v.character.control = FALSE; + event.v.character.alt = TRUE; + event.v.character.consumed = FALSE; + + if ( event.v.character.ch != 18 ) + { + int cnt; + + for ( cnt = 0; vk_table[cnt].xi_key != 0; ++cnt ) + { + if ( vk_table[cnt].v_key == event.v.character.ch ) + { + event.v.character.ch = vk_table[cnt].xi_key; + event.v.character.shift = vk_table[cnt].shift; + break; + } + } + { + EVENT xvt_event; + EVENT* old_cur_event = cur_xvt_event; + xvt_event.v.chr.ch = LONGFROMMP( pmsg->mp2 ); + xvt_event.v.chr.shift = FALSE; + xvt_event.v.chr.control = FALSE; + + cur_xvt_event = &xvt_event; + ( *ehlt->event_handler ) ( ( XinWindow ) ehlt->win, &event ); + cur_xvt_event = old_cur_event; + } + return !event.v.character.consumed; + + } + } + } + return TRUE; +} + +#endif + +static char *xin_help_file_name = NULL; + +/*START*/ +/* Native help (only implemented on Windows - these calls do nothing elsewhere) */ + +void +XinHelpFileNameSet( char *filename ) +{ +/*END*/ + if (xin_help_file_name != NULL) + XinMemoryFree( xin_help_file_name ); + xin_help_file_name = (char *)XinMemoryAlloc( (strlen( filename ) + 1) * sizeof( char ) ); + strcpy( xin_help_file_name, filename ); +/*START*/ +} + +char * +XinHelpFileNameGet() +{ +/*END*/ + return xin_help_file_name; +/*START*/ +} + +/* This function only does anything on Windows. */ +BOOLEAN +XinNativeHelp( XinWindow win, char *help_key ) +{ +/*END*/ +#if XIWS == XIWS_WIN + if (xin_help_file_name != NULL && win != XI_NULL_WINDOW && + help_key != NULL) + { + return WinHelp( (HWND)XinWindowNativeGet( win ), xin_help_file_name, + HELP_KEY, (long)help_key ); + } + return FALSE; +#else + return FALSE; +#endif +} diff --git a/src/xi01/xiport.h b/src/xi01/xiport.h new file mode 100644 index 000000000..f6605e1bd --- /dev/null +++ b/src/xi01/xiport.h @@ -0,0 +1,871 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +/*============================================================================== +* Note: Portions not implemented on Motif are commented NOTIMP. +* Portions removed from the header are commented out and marked REMOVED +* New parts are marked with NEW +*============================================================================*/ + +#ifndef XIN_INCL_XIPORT_H +#define XIN_INCL_XIPORT_H + +#ifdef WIN32 +#if XIAGADLL == 1 + #define XIDLL __declspec(dllexport) +#else + #define XIDLL __declspec(dllimport) +#endif +#else +#define XIDLL +#endif + +#define R4 +#include "xires.h" + +#include "stdio.h" +#include "assert.h" +#include "string.h" +#include "math.h" +#include "stdlib.h" +#include "ctype.h" + +/* This code is not needed when using the XVT define for native +#if XIWS == XIWS_PM +#define INCL_DOS +#define INCL_WIN +#define INCL_GPI +#define COLOR pm_COLOR +#define UINT pm_UINT +#define ULONG pm_ULONG +#include +#undef COLOR +#undef UINT +#undef ULONG +#define INTERNAL +#endif +*/ + +/* +We don't really use the following, we just define them so that they are removed +from the XI source code when we don't use XVT. +*/ +#ifndef XVT_CALLCONV1 +#define XVT_CALLCONV1 +#endif + +#ifndef XVT_CC_ARGS +#define XVT_CC_ARGS(a) a +#endif + +/* Set an object's memory to all zeros */ +#define XIN_CLEAR(obj) memset(&obj, 0, sizeof(obj)); + +#define XIN_INC_TYPE( s_T, T ) typedef struct s_T T +#define XIN_INC_PTR_TYPE( s_T, T ) typedef struct s_T *T +#define XIN_FAKE_TYPE( s_T, T ) typedef struct s_T {int x;} T +#define XIN_FAKE_PTR_TYPE( s_T, T ) typedef struct s_T {int x;} *T + +#ifndef BOOLEAN +#define BOOLEAN short +#define FALSE 0 +#define TRUE 1 +#endif + +typedef enum +{ + XinFlagNotSet, + XinFlagTrue, + XinFlagFalse +} XinFlag; + +typedef enum +{ + XinClipboardFormatText, + XinClipboardFormatBitmap /* NOTIMP */ +} XinClipboardFormat; + +typedef struct +{ + short v; + short h; +} XinPoint; + +typedef struct +{ + short top; + short left; + short bottom; + short right; +} XinRect; + +typedef unsigned long XinColor; + +#ifdef XIN_INTERNAL_WINDOW +XIN_INC_PTR_TYPE( s_XinWindow, XinWindow ); +#else +XIN_FAKE_PTR_TYPE( s_XinWindow, XinWindow ); +#endif + +#define XI_NULL_WINDOW ((XinWindow)0L) + +typedef enum +{ + XinEventCreate, + XinEventDestroy, + XinEventFocus, + XinEventResize, + XinEventPaint, + XinEventCloseButton, + XinEventMouseDown, + XinEventMouseUp, + XinEventMouseMove, + XinEventMouseDouble, + XinEventCharacter, + XinEventVScroll, /* NOTIMP */ + XinEventHScroll, /* NOTIMP */ + XinEventMenuCommand, + XinEventControl, + XinEventTimer, + XinEventQuit, + XinEventHelp, /* NOTIMP */ + XinEventFont, /* NOTIMP */ + XinEventUser +} XinEventType; + +typedef enum +{ + XinScrollBarActionNone, + XinScrollBarActionLineUp, + XinScrollBarActionLineDown, + XinScrollBarActionPageUp, + XinScrollBarActionPageDown, + XinScrollBarActionThumb, + XinScrollBarActionThumbTrack +} XinScrollBarAction; + +typedef int XinMenuTag; + +/* NEW */ +typedef enum +{ + XinBorderDouble, + XinBorderSingle, + XinBorderSizable, + XinBorderFixed, + XinBorderNone /* NOTIMP -- requires child window support */ +} XinBorderStyle; + +/* NEW */ +typedef enum +{ + XinModeless, + XinModalReturn, + XinModalWait, + XinModalAutoclose +} XinWindowMode; + +typedef enum +{ + XinWindowTypeDocument, + XinWindowTypePrint, + XinWindowTypeTask, + XinWindowTypeScreen, + XinWindowTypeButton, /* NOTIMP */ + XinWindowTypeRadioButton, /* NOTIMP */ + XinWindowTypeCheckBox, /* NOTIMP */ + XinWindowTypeHorizontalScrollBar, + XinWindowTypeVerticalScrollBar +} XinWindowType; + +typedef struct +{ + XinWindowType type; + XinWindow win; + union + { + struct + { + XinScrollBarAction action; + short position; + } scroll; + } v; +} XinControlInformation; + +typedef enum +{ + XinScrollBarTypeHorizontal, /* NOTIMP -- no scrollbars on window borders */ + XinScrollBarTypeVertical, /* NOTIMP -- no scrollbars on window borders */ + XinScrollBarTypeEither +} XinScrollBarType; + +typedef enum +{ + XinFontFamilySystem, + XinFontFamilyFixed, + XinFontFamilyTimes, + XinFontFamilyHelvetica, + XinFontFamilyOther +} XinFontFamily; + +#ifdef XIN_INTERNAL_FONT +/* Use an incomplete type so that complete type can be defined internally */ +XIN_INC_TYPE( s_XinFont, XinFont ); +#else +/* Use a complete but fake type, so that Borland does not complain */ +XIN_FAKE_TYPE( s_XinFont, XinFont ); +#endif + +#ifdef XIN_INTERNAL_BITMAP +XIN_INC_TYPE( s_XinBitmap, XinBitmap ); +#else +XIN_FAKE_TYPE( s_XinBitmap, XinBitmap ); +#endif + +typedef struct +{ + XinEventType type; + union + { + struct + { + XinPoint where; + BOOLEAN shift; + BOOLEAN control; + BOOLEAN alt; + short button; + } mouse; + struct + { + short ch; + BOOLEAN shift; + BOOLEAN control; + BOOLEAN alt; + BOOLEAN consumed; /* For internal use only */ + } character; + struct + { + BOOLEAN active; + } focus; + struct + { + BOOLEAN query; /* NOTIMP -- always FALSE on Motif */ + } quit; + struct + { + XinScrollBarAction action; + short position; + } scroll; + struct + { + XinMenuTag tag; + BOOLEAN shift; + BOOLEAN control; + } menu_command; + struct + { + BOOLEAN minimized; + short height; + short width; + } resize; + struct + { + short control_id; + XinControlInformation ctrl_info; + } control; + struct + { + XinRect rect; + } paint; + struct + { + long id; + } timer; + struct + { + XinFont *font; + } font; + struct + { + XinWindow obj; + XinMenuTag tag; + long topic_id; + } help; + struct + { + long id; + void *ptr; + } user; + } v; +} XinEvent; + +#ifdef __cplusplus +extern "C" +{ +#endif + typedef void ( *XinWindowEventHandler ) ( XinWindow win, XinEvent * ep ); + typedef BOOLEAN( *XinPrintHandler ) ( long app_data ); +#ifdef __cplusplus +} + +#endif + +typedef struct s_XinMenuItem +{ + XinMenuTag tag; + char *text; /* ~ in text indicates mnemonic */ + BOOLEAN enabled; + BOOLEAN checked; + BOOLEAN checkable; + BOOLEAN separator; + int nbr_children; + struct s_XinMenuItem *children; +} XinMenuItem; + +/* NEW */ +typedef struct +{ + int nbr_items; + XinMenuItem *items; +} XinMenu; + +typedef struct +{ + int control_id; + XinWindowType type; + XinRect *p_rect; + char *title; /* NEW -- NULL means no titlebar */ + XinBorderStyle border_style; /* NEW */ + BOOLEAN vertical_scroll_bar; /* NOTIMP */ + BOOLEAN horizontal_scroll_bar;/* NOTIMP */ + BOOLEAN close_button; + BOOLEAN visible; + BOOLEAN enabled; + BOOLEAN iconizable; + BOOLEAN iconized; + BOOLEAN maximized; + XinWindowMode mode; /* NEW */ + XinWindow parent; /* See note1 below */ + XinMenu *menu; /* New -- no menubar if NULL */ + int menu_bar_rid; /* NOTIMP */ + int icon_rid; /* Implemented via XPM on Motif -- requires + * linkage of icons */ + long app_data; + XinWindowEventHandler eh; + XinColor back_color; /* NEW -- window's default background. + * Influences caret color */ + XinFont *font; /* NEW -- only used for native controls */ +} XinWindowDef; + +/* +{ + XinWindowDef Def; + + MEMCLEAR(Def); + Def.control_id = ; + Def.type = ; + Def.p_rect = ; + Def.title = ; + Def.border_style = ; + Def.vertical_scroll_bar = ; + Def.horizontal_scroll_bar = ; + Def.close_button = ; + Def.visible = ; + Def.enabled = ; + Def.iconizable = ; + Def.iconized = ; + Def.maximized = ; + Def.mode = ; + Def.parent = ; + Def.menu = ; + Def.menu_bar_rid = ; + Def.icon_rid = ; + Def.app_data = ; + Def.eh = ; + Def.back_color = ; +} +*/ + +/* Note1: if mode == +* XinModeless, then parent argument may be task, screen or toplevel window. Setting the +* parent to toplevel window enforfces stack-above-parent and iconize-with-parent. +* XinModalReturn or XinModalWait, then parent argument may be task, screen or toplevel window. +* Task or screen window is application-modal (although windows may still be closed). +* XinModalAutoclose, then parent must be a toplevel window. Autoclose windows are closed before +* any user input is sent to the parent window. +*/ + +typedef struct +{ + char *task_win_title; /* NOTIMP */ + char *appl_name; /* NOTIMP */ + int menu_bar_rid; /* NOTIMP */ + XinWindowEventHandler eh; + XinRect *p_rect; /* NOTIMP */ + BOOLEAN iconized; /* NOTIMP */ + BOOLEAN maximized; /* NOTIMP */ + BOOLEAN use_mdi; /* NOTIMP */ + BOOLEAN drawable_task_win; + BOOLEAN app_is_unique; /* Don't allow multiple instances of the application to run. */ + int argc; + char **argv; +} XinSystemSetup; + +typedef unsigned long XinCursor; + +/* NEW */ +typedef enum +{ + XinPenHollow, + XinPenSolid, + XinPenDashed, + XinPenDotted, // Added by Guy +} XinPenPattern; + +/* NEW */ +typedef enum +{ + XinBrushHollow, + XinBrushSolid, + XinBrushHatch +} XinBrushPattern; + +typedef struct +{ + short width; + XinPenPattern pattern; /* Changed to XinPenPattern */ + XinColor fore_color; /* NEW color of pen */ +} XinPen; + +typedef struct +{ + XinBrushPattern pattern; /* Changed to XinBrushPattern */ + XinColor fore_color; /* NEW fore_color allows future back_color with + * hatched brushes */ +} XinBrush; + +typedef enum +{ + XinDrawModeCopy, + XinDrawModeXor /* See Note2 */ +} XinDrawMode; + +/* Note2: XOR mode, if drawn on pixels equalling the back_color of the window, will attempt +* to produce the fore_color of the tool (pen/brush/text). Drawing on pixels of fore_color +* will attempt to produce back_color. The operation is self-reversing. +*/ + +typedef struct +{ + XinPen pen; + XinBrush brush; + XinDrawMode draw_mode; + XinColor text_fore_color; + XinColor text_back_color; + BOOLEAN opaque_text; +} XinDrawTools; + +typedef enum +{ + XinResponse1, + XinResponse2, + XinResponse3 +} XinResponse; + + +typedef enum +{ + XinMetricIconHeight, /* Will pick a constant reflecting the WM + * restirctions */ + XinMetricIconWidth, /* Will pick a constant reflecting the WM + * restirctions */ + XinMetricHorizontalScrollBarHeight, + XinMetricVerticalScrollBarWidth, + XinMetricScreenHeight, + XinMetricScreenWidth, + XinMetricSizableFrameHeight, /* Guess on Motif */ + XinMetricSizableFrameWidth, /* Guess on Motif */ + XinMetricDoubleFrameHeight, /* Guess on Motif */ + XinMetricDoubleFrameWidth, /* Guess on Motif */ + XinMetricFrameHeight, /* Guess on Motif */ + XinMetricFrameWidth, /* Guess on Motif */ + XinMetricMenuHeight, /* Guess on Motif */ + XinMetricTitleHeight, /* Guess on Motif */ + XinMetricVerticalStagger, + XinMetricHorizontalStagger, + XinMetricScreenHRes, + XinMetricScreenVRes +} XinMetricType; + +#define XI_FILE_MAX 256 +typedef char XinDirectory[XI_FILE_MAX + 1]; + +typedef enum +{ + XinFileGood, + XinFileCancel, + XinFileBad +} XinFileResult; + +typedef enum +{ + XinOpenFileDialog, + XinSaveFileDialog +} XinFileDialogType; + +typedef struct +{ + char *type; + XinDirectory directory; + char file_name[XI_FILE_MAX + 1]; +} XinFileSpec; + +typedef struct +{ + char *type; + char *pattern; + BOOLEAN include_dirs; + BOOLEAN dirs_only; +} XinFileListSpec; + +typedef struct +{ + int nbr_files; + char **file_names; +} XinFileList; + +#ifdef XIN_INTERNAL_PRINT_RECORD +/* Use an incomplete type so that complete type can be defined internally */ +XIN_INC_TYPE( s_XinPrintRecord, XinPrintRecord ); +#else +/* Use a complete but fake type, so that Borland does not complain */ +XIN_FAKE_TYPE( s_XinPrintRecord, XinPrintRecord ); +#endif + +#ifndef NOREF +#define NOREF(a) a = a +#endif + +#ifndef assert4 +#define assert4(a, b, c, d) if (!(a)) XinError( (c),XinSeverityFatal,0L ) +#endif + +#define XI_KEY_DEL 127 +#define XI_KEY_UP 301 +#define XI_KEY_DOWN 302 +#define XI_KEY_RIGHT 303 +#define XI_KEY_LEFT 304 +#define XI_KEY_PREV 305 +#define XI_KEY_NEXT 306 +#define XI_KEY_LHOME 307 +#define XI_KEY_LEND 308 +#define XI_KEY_HOME 309 +#define XI_KEY_END 310 +#define XI_KEY_WLEFT 313 +#define XI_KEY_WRIGHT 314 +#define XI_KEY_BTAB 315 +#define XI_KEY_CLEAR 317 +#define XI_KEY_F1 331 +#define XI_KEY_F2 332 +#define XI_KEY_F3 333 +#define XI_KEY_F4 334 +#define XI_KEY_F5 335 +#define XI_KEY_F6 336 +#define XI_KEY_F7 337 +#define XI_KEY_F8 338 +#define XI_KEY_F9 339 +#define XI_KEY_F10 340 +#define XI_KEY_F11 341 +#define XI_KEY_F12 342 + +#define XI_CURSOR_ARROW 0 +#define XI_CURSOR_IBEAM 1 +#define XI_CURSOR_CROSS 2 +#define XI_CURSOR_WAIT 3 + +#define XI_COLOR_RED 0x00FF0000L +#define XI_COLOR_GREEN 0x0000FF00L +#define XI_COLOR_BLUE 0x000000FFL +#define XI_COLOR_CYAN 0x0000FFFFL +#define XI_COLOR_MAGENTA 0x00FF00FFL +#define XI_COLOR_YELLOW 0x00FFFF00L +#define XI_COLOR_BLACK 0x80000000L +#define XI_COLOR_DKGRAY 0x00404040L +#define XI_COLOR_GRAY 0x00808080L +#define XI_COLOR_LTGRAY 0x00C0C0C0L +#define XI_COLOR_WHITE 0x00FFFFFFL + + +/* New -- values for Motif */ +#if XIWS == XIWS_XM +#define XI_CLIP_EOL "\012" +#else +#define XI_CLIP_EOL "\015\012" +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Memory */ + void *XinMemoryAlloc( size_t size ); + void XinMemoryFree( void *ptr ); + void *XinMemoryRealloc( void *ptr, size_t size ); + void *XinMemoryZeroAlloc( size_t size ); + +/* Dialogs */ + XinResponse XinDialogAsk( char *btn_text_1, char *btn_text_2, + char *btn_text_3, char *fmt,... ); + void XinDialogError( char *format,... ); + void XinDialogFatal( char *format,... ); + XinFileResult XinDialogFile( char *message, XinFileSpec * spec, + XinFileDialogType type ); + BOOLEAN XinDialogFont( XinFont * font ); + void XinDialogNote( char *format,... ); + BOOLEAN XinDialogPrinterSetup( XinPrintRecord * rec ); + char *XinDialogStringPrompt( char *message, char *response, + int size_response ); + +/* Rectangles */ + BOOLEAN XinRectEmpty( XinRect * rect ); + XinRect *XinRectIntersect( XinRect * result, XinRect * r1, XinRect * r2 ); + BOOLEAN XinRectPointContained( XinRect * rect, XinPoint * point ); + XinRect *XinRectEnclose( XinRect * dst, XinRect * src1, XinRect * src2 ); + +/* Windows and drawing */ + long XinWindowAppDataGet( XinWindow win ); + void XinWindowAppDataSet( XinWindow win, long app_data ); + void XinWindowArcDraw( XinWindow win, XinRect* ellipse, XinPoint* start, XinPoint* stop ); + void XinWindowBitmapDraw( XinWindow win, XinBitmap * bitmap, XinRect * dest, + XinRect * source ); + void XinWindowBrushSet( XinWindow win, XinBrush * brush ); + void XinWindowCaretOff( XinWindow win ); + void XinWindowCaretOn( XinWindow win, int x, int y, int height, + XinColor assumed_back_color, XinRect * clip_rct ); + void XinWindowCheckBox( XinWindow win, BOOLEAN check ); /* NOTIMP */ + void XinWindowCheckRadioButton( XinWindow win, XinWindow * wins, /* NOTIMP */ + int nbr_windows ); + BOOLEAN XinWindowClipGet( XinWindow win, XinRect * rect ); + void XinWindowClipSet( XinWindow Win, XinRect * rect ); + void XinWindowColorTextBackSet( XinWindow win, XinColor color ); /* Added Text */ + void XinWindowColorTextForeSet( XinWindow win, XinColor color ); /* Added Text */ + XinWindow XinWindowCreate( XinWindowDef * def ); + void XinWindowCursorSet( XinWindow win, XinCursor cursor ); + void XinWindowDestroy( XinWindow win ); + + XinDrawMode XinWindowDrawModeGet( XinWindow win ); + void XinWindowDrawModeSet( XinWindow win, XinDrawMode mode ); + XinDrawTools *XinWindowDrawToolsGet( XinWindow win, XinDrawTools * tools ); + XinDrawTools *XinWindowDrawToolsNormalGet( XinDrawTools * tools ); + void XinWindowDrawToolsSet( XinWindow win, XinDrawTools * tools ); + XinWindow XinWindowDropDownParentGet( XinWindow creating_win ); + void XinWindowEllipseDraw( XinWindow win, XinRect* rect ); + void XinWindowEnable( XinWindow win, BOOLEAN enable ); /* NOTIMP */ + void XinWindowEventUserSend( XinWindow win, long id, void *ptr ); + void XinWindowFontMap( XinWindow win, XinFont * font ); + XinWindow XinWindowFocusGet( void ); + void XinWindowFocusSet( XinWindow win ); /* May be ineffective */ + void XinWindowFrontSet( XinWindow win ); + void XinWindowHotkeySet( XinWindow win, char ch ); + void XinWindowIconDraw( XinWindow win, int x, int y, int icon_rid, + XinColor fore_color, XinColor back_color ); + void XinWindowLineDraw( XinWindow win, XinPoint * point ); + void XinWindowLineMoveTo( XinWindow win, XinPoint * point ); + void XinWindowMouseRelease( void ); + void XinWindowMouseTrap( XinWindow win, + BOOLEAN continuous_mouse_moves ); + long XinWindowNativeGet( XinWindow win ); + void XinWindowPaintForce( XinWindow win ); + BOOLEAN XinWindowPaintNeeds( XinWindow win, XinRect * p_rect ); + XinWindow XinWindowParentGet( XinWindow win ); + void XinWindowPenSet( XinWindow win, XinPen * pen ); + void XinWindowPieDraw( XinWindow win, XinRect* ellipse, XinPoint* start, XinPoint* stop ); + void XinWindowPointsTranslate( XinWindow from_win, XinWindow to_win, + XinPoint * points, int nbr_points ); + void XinWindowPolygonDraw( XinWindow win, XinPoint* points, int nbr_points ); + void XinWindowRectDraw( XinWindow win, XinRect * rect ); + void XinWindowDottedRectDraw( XinWindow win, XinRect * rect ); /* Added by Guy */ + void XinWindowRoundRectDraw( XinWindow win, XinRect * rect, int rh, int rv ); /* Added by Guy */ + void XinWindowShadedRectDraw( XinWindow win, XinRect * rect ); /* Added by Guy */ + void XinWindowCheckMarkDraw( XinWindow win, XinRect * rect ); /* Added by Guy */ + + XinRect *XinWindowRectGet( XinWindow win, XinRect * p_rect ); + void XinWindowRectInvalidate( XinWindow win, XinRect * rect ); + XinRect *XinWindowRectOuterGet( XinWindow win, XinRect * p_rect ); + void XinWindowRectScroll( XinWindow win, XinRect * p_rect, + int dh, int dv ); + void XinWindowRectSet( XinWindow win, XinRect * rect ); + void XinWindowRectTranslate( XinWindow from_win, XinWindow to_win, + XinRect * rect ); + XinWindow XinWindowScreenGet( void ); + void XinWindowShow( XinWindow win, BOOLEAN show ); + XinWindow XinWindowTaskGet( void ); + void XinWindowTextOpaqueSet( XinWindow win, BOOLEAN opaque ); + void XinWindowTextDraw( XinWindow win, XinFont * font, int x, int y, + char *buf, int len ); + void XinWindowTextRotateDraw( XinWindow win, XinFont* font, int x, int y, + int rotation, char* buf, int len ); + void XinWindowTimerKill( XinWindow win, long timer_id ); + long XinWindowTimerSet( XinWindow win, long millisecs ); + char *XinWindowTitleGet( XinWindow win ); + void XinWindowTitleSet( XinWindow win, const char *title ); +#if XIWS == XIWS_XM + long XinWindowGetWidget( XinWindow win ); /* Return value is really a + * Widget */ +#endif + +/* Scroll Bars */ + int XinScrollBarPositionGet( XinWindow win, XinScrollBarType type ); + void XinScrollBarPositionSet( XinWindow win, XinScrollBarType type, + int position ); + int XinScrollBarProportionGet( XinWindow win, XinScrollBarType type ); + void XinScrollBarRangeGet( XinWindow win, XinScrollBarType type, + int *p_min, int *p_max ); + void XinScrollBarSet( XinWindow win, XinScrollBarType type, + int min_val, int max_val, + int proportion, int pos ); + +/* Clip Board */ + BOOLEAN XinClipboardFormatAvail( XinClipboardFormat format ); + void *XinClipboardGet( XinClipboardFormat format, long *size ); + void XinClipboardPut( XinClipboardFormat format, long size, + void *data ); + +/* Application */ + void XinAppCleanup( void ); + void XinAppQuitOk( void ); /* NOP on Motif */ + void XinAppTerminate( void ); + void XinAppSystemSetupInit( XinSystemSetup * setup ); + void XinDebugPrintf( char *format,... ); /* NOTIMP */ + void XinPendingEventsProcess( void ); + +/* Miscellaneous */ + void XinBeep( void ); + XinColor XinColorMake( int red, int green, int blue ); + BOOLEAN XinStringMatch( char *string, char *pattern, + BOOLEAN case_sensitive ); + void XinCursorWait( void ); + long XinMetricGet( XinMetricType type ); + void XinCoalesceInvalidates( XinWindow win, BOOLEAN coalesce ); + void XinInitBuffer( void ); +#ifdef XI_USE_XVT + void XinXvtEventGet( void *xvtp ); + char *XinXvtEventTextGet( void *xvtp ); + void XinXvtWindowRegister( XinWindow win, XinWindowEventHandler eh ); +#endif + +/* Menus */ + XinMenuItem *XinMenuAdd( XinMenu * menu, int index, XinMenuItem * item ); + XinMenu *XinMenuCreate( void ); + BOOLEAN XinMenuDelete( XinMenu * menu, int index ); + XinMenu *XinMenuDuplicate( XinMenu * menu ); + void XinMenuFree( XinMenu * menu ); + XinMenuItem *XinMenuItemAdd( XinMenuItem * item, int index, + XinMenuItem * child ); + XinMenuItem *XinMenuItemCreate( char *text ); + XinMenuItem *XinMenuItemDuplicate( XinMenuItem * item ); + BOOLEAN XinMenuItemDelete( XinMenuItem * item, int index ); + void XinMenuItemFree( XinMenuItem * item ); + void XinMenuItemTextSet( XinMenuItem * item, char *text ); + + void XinWindowMenuFontSet( XinWindow win, XinFont * font ); /* NOTIMP */ + XinMenu *XinWindowMenuGet( XinWindow win, XinMenuTag tag ); /* menubar if tag==0 */ + void XinWindowMenuItemCheck( XinWindow win, XinMenuTag tag, + BOOLEAN check ); + void XinWindowMenuItemEnable( XinWindow win, XinMenuTag tag, + BOOLEAN enable ); + XinMenuItem *XinWindowMenuItemGet( XinWindow win, XinMenuTag tag ); + BOOLEAN XinWindowMenuItemIsChecked( XinWindow win, XinMenuTag tag ); + BOOLEAN XinWindowMenuItemIsEnabled( XinWindow win, XinMenuTag tag ); + char *XinWindowMenuItemTextGet( XinWindow win, XinMenuTag tag ); + void XinWindowMenuItemTextSet( XinWindow win, XinMenuTag tag, char *text ); + void XinWindowMenuReplace( XinWindow win, XinMenuTag tag, XinMenu * menu ); /* menubar if tag==0 */ + +/* Fonts */ + BOOLEAN XinFontBoldGet( XinFont * font ); + void XinFontBoldSet( XinFont * font, BOOLEAN flag ); + BOOLEAN XinFontCompare( XinFont * font1, XinFont * font2 ); + void XinFontCopy( XinFont ** to, XinFont * from ); + XinFont *XinFontCreate( void ); + void XinFontDestroy( XinFont * font ); + XinFontFamily XinFontFamilyGet( XinFont * font ); + void XinFontFamilySet( XinFont * font, XinFontFamily family ); + BOOLEAN XinFontIsMapped( XinFont * font ); + BOOLEAN XinFontItalicGet( XinFont * font ); + void XinFontItalicSet( XinFont * font, BOOLEAN flag ); + void XinFontMetricsGet( XinFont * font, int *p_leading, int *p_ascent, + int *p_descent ); + int XinFontSizeGet( XinFont * font ); + void XinFontSizeSet( XinFont * font, int size ); + int XinFontTextWidthGet( XinFont * font, char *text, int len ); + void XinFontNativeConvert( XinFont * font ); +#ifdef XI_USE_XVT + XinFont *XinFontXvtConvert( void *font_id ); + void *XinFontXvtConvertBack( XinFont * font_id ); + void XinFontXvtDestroy( void* font_id ); +#endif + void XinFontUnmap( XinFont* font_id ); /* RGM: Font unmap hack */ + +/* Bitmaps */ + void XinBitmapDestroy( XinBitmap * bitmap ); + XinBitmap *XinBitmapRead( char *filename ); + XinBitmap *XinBitmapReadRes( short id ); + void XinBitmapSizeGet( XinBitmap * bitmap, short *pwidth, short *pheight ); + +/* Printing */ + XinRect *XinPrintBandNext( void ); + BOOLEAN XinPrintPageEnd( XinPrintRecord * rec ); + BOOLEAN XinPrintPageStart( XinPrintRecord * rec ); + XinPrintRecord *XinPrintRecordCreate( int *p_size ); + void XinPrintRecordDestroy( XinPrintRecord * rec ); + BOOLEAN XinPrintRecordValidate( XinPrintRecord * rec ); + BOOLEAN XinPrintThreadStart( XinPrintHandler func, long app_data ); + XinWindow XinPrintWindowCreate( XinPrintRecord * rec, char *title ); + void XinPrintWindowDestroy( XinWindow win ); + void XinPrintRecordMetricsGet( XinPrintRecord * rec, long * height, long * width, + long * vres, long * hres ); + +/* Files and Directories */ + BOOLEAN XinDirectoryAbsoluteGet( char *full_name, XinDirectory * dir ); + BOOLEAN XinDirectoryCurrentGet( XinDirectory * dir ); + BOOLEAN XinDirectoryCurrentSet( XinDirectory * dir ); + XinFileList *XinFileListGet( XinFileListSpec * spec ); + +/* NEW error handling */ + typedef enum + { + XinSeverityWarning, XinSeverityFatal + } XinSeverity; + typedef BOOLEAN( *XinErrorHandler ) ( int errocde, XinSeverity severity, long app_data ); +/* Note: return value of error handler is TRUE if app should terminate, FALSE to continue */ + + void XinError( int errcode, XinSeverity severity, long app_data ); + XinErrorHandler XinErrorHandlerGet( void ); + void XinErrorHandlerSet( XinErrorHandler handler ); + + BOOLEAN XinErrorDefaultHandler( int errcode, XinSeverity severity, + long app_data ); + void XinIconSizeGet( int icon_rid, int *widthp, int *heightp ); + +/* Native help (only implemented on Windows - these calls do nothing elsewhere) */ + void XinHelpFileNameSet( char *filename ); + char *XinHelpFileNameGet(); + BOOLEAN XinNativeHelp( XinWindow win, char *help_key ); + +#ifdef __cplusplus +} /* End of extern "C" */ + +#endif + +/* Range of errors used internally by Xin */ +#define XIN_ERRCODE_INTERNAL_MIN 1000 +#define XIN_ERRCODE_INTERNAL_MAX 2000 + +#endif diff --git a/src/xi01/xiport2.h b/src/xi01/xiport2.h new file mode 100644 index 000000000..79fc62854 --- /dev/null +++ b/src/xi01/xiport2.h @@ -0,0 +1,17 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ +#define TEMP_BUFFER_SIZE 10000 + +extern XinWindowEventHandler xin_teh; +extern char *xin_buffer; +extern BOOLEAN xin_use_mdi_flag; +extern BOOLEAN xin_xvt_initialized; + +XIDLL long XinXvtEventHandler( WINDOW win, EVENT * ep ); diff --git a/src/xi01/xires.h b/src/xi01/xires.h new file mode 100644 index 000000000..6411aa033 --- /dev/null +++ b/src/xi01/xires.h @@ -0,0 +1,105 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XIWS_WIN 101 +#define XIWS_XM 102 +#define XIWS_MAC 103 +#define XIWS_PM 104 +#define XIWS_WM 105 +#define XIWS_WXGTK 106 + +#if !defined(XI_USE_XVT) && !defined(XI_USE_XM) && !defined(XI_USE_WIN) +#define XI_USE_XVT +#endif + +#ifdef LINUX +#define XVTWS WXGTKWS +#endif + +#ifdef XI_USE_XVT +#include "xvt_env.h" + +#ifndef XI_R4_API +#undef XIWS_WIN +#define XIWS_WIN WINWS +#undef XIWS_XM +#define XIWS_XM MTFWS +#undef XIWS_MAC +#define XIWS_MAC MACWS +#undef XIWS_PM +#define XIWS_PM PMWS +#undef XIWS_WM +#define XIWS_WM WMWS +#endif + +#if XVTWS == MACWS +#define XIWS XIWS_MAC +#elif XVTWS == PMWS +#define XIWS XIWS_PM +#elif XVTWS == WIN32WS || XVTWS == WIN16WS +#define XIWS XIWS_WIN +#elif XVTWS == WMWS +#define XIWS XIWS_WM +#elif XVTWS == MTFWS || XVTWS == XOLWS +#define XIWS XIWS_XM +#elif XVTWS == WXGTKWS +#define XIWS XIWS_WXGTK +#endif + +#endif + +#ifdef XI_USE_XM +#define XIWS XIWS_XM +#define EOL_SEQ "\n" +#define SZ_FNAME 256 +#endif + +#ifdef XI_USE_WIN +#define XIWS XIWS_WIN +#define EOL_SEQ "\n" +#define SZ_FNAME 256 +#endif + +#define XI_CURSOR_RESIZE 8001 +#define XI_CURSOR_HAND 8002 +#define XI_CURSOR_VRESIZE 8003 + +#ifndef COMBO_ICON +#define COMBO_ICON 1026 +#endif + +#define NULL_MENU_RID 8000 + +#define XI_MENU_FILE 32000 +#define XI_MENU_FILE_NEW (XI_MENU_FILE+1) +#define XI_MENU_FILE_OPEN (XI_MENU_FILE+2) +#define XI_MENU_FILE_CLOSE (XI_MENU_FILE+3) +#define XI_MENU_FILE_SAVE (XI_MENU_FILE+4) +#define XI_MENU_FILE_SAVE_AS (XI_MENU_FILE+5) +#define XI_MENU_FILE_REVERT (XI_MENU_FILE+6) +#define XI_MENU_FILE_PG_SETUP (XI_MENU_FILE+7) +#define XI_MENU_FILE_PRINT (XI_MENU_FILE+8) +#define XI_MENU_FILE_QUIT (XI_MENU_FILE+9) +#define XI_MENU_FILE_ABOUT (XI_MENU_FILE+10) + +#define XI_MENU_EDIT 32025 +#define XI_MENU_EDIT_UNDO (XI_MENU_EDIT+1) +#define XI_MENU_EDIT_CUT (XI_MENU_EDIT+2) +#define XI_MENU_EDIT_COPY (XI_MENU_EDIT+3) +#define XI_MENU_EDIT_PASTE (XI_MENU_EDIT+4) +#define XI_MENU_EDIT_CLEAR (XI_MENU_EDIT+5) + +#define XI_MENU_FONT 32030 +#define XI_MENU_FONT_SELECT 32031 + +#define XI_MENU_WIN 32100 +#define XI_MENU_WIN_CASCADE (XI_MENU_WIN+1) +#define XI_MENU_WIN_TILE_HORZ (XI_MENU_WIN+2) +#define XI_MENU_WIN_TILE_VERT (XI_MENU_WIN+3) +#define XI_MENU_WIN_CLOSE_ALL (XI_MENU_WIN+4) diff --git a/src/xi01/xisetup.c b/src/xi01/xisetup.c new file mode 100644 index 000000000..defe3bcd8 --- /dev/null +++ b/src/xi01/xisetup.c @@ -0,0 +1,20 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#include "xiport.h" + +void +XinAppSystemSetupInit( XinSystemSetup * SystemSetup ) +{ + SystemSetup->task_win_title = "DUMMY"; + SystemSetup->appl_name = "dummy"; + SystemSetup->menu_bar_rid = 0; + SystemSetup->eh = NULL; +} diff --git a/src/xi01/xistx.c b/src/xi01/xistx.c new file mode 100644 index 000000000..57e40f67b --- /dev/null +++ b/src/xi01/xistx.c @@ -0,0 +1,1698 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#include "xi.h" +#include "xitext.h" +#include "xistx.h" +#include "xiutils.h" +#include "xi_int.h" +#include + +/* error codes 30100 - 30104 */ + +#if XIWS != XIWS_WM +#define BORDER_WIDTH 1 +#define BORDER_SPACE 1 +#define DDD_RECT_DEPTH 2 +#else +#define BORDER_WIDTH_X 8 +#define BORDER_WIDTH_Y 0 +#define BORDER_SPACE_X 0 +#define BORDER_SPACE_Y 0 +#define DDD_RECT_WIDTH 0 +#define CHR_LEFTBRACKET "[" +#define CHR_RIGHTBRACKET "]" +#endif + +#define STX_REDRAW_ATR (XI_ATR_VISIBLE | XI_ATR_ENABLED | XI_ATR_RJUST | XI_ATR_PASSWORD) + +#ifdef XI_USE_TX_SUPPORT +static TXEDIT stx_get_txedit( STX stx ); +static BOOLEAN convert_event_back( EVENT * ep, XinEvent * xiep ); + +#if 0 +static void draw_text_edit_border( STX_DATA * stxp ); + +#endif +#endif + +static void +draw_back_rect( STX_DATA * stxp, XinRect * r ) +{ + XinDrawTools dt; + + XinWindowDrawToolsNormalGet( &dt ); + dt.pen.width = 1; + dt.pen.pattern = XinPenHollow; + dt.brush.pattern = XinBrushSolid; + if ( stxp->has_focus ) + dt.brush.fore_color = stxp->active_back_color; + else + { + if (stxp->attrib & XI_ATR_ENABLED) + dt.brush.fore_color = stxp->back_color; + else + dt.brush.fore_color = stxp->disabled_back_color; + } + dt.draw_mode = XinDrawModeCopy; + XinWindowDrawToolsSet( stxp->win, &dt ); + +#if XIWS == XIWS_MAC + if ( stxp->xi_text ) + xi_text_rect_get_adjusted( stxp->xi_text, r ); +#endif + xi_draw_rect( stxp->win, r ); +} + +static void +stx_redraw( STX stx, BOOLEAN update ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + BOOLEAN do_border = FALSE; + unsigned long tattrib; + XinRect rct; + XinColor border_color = 0L; + +#if XIWS == XIWS_WM + XinRect r; + +#endif + +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) && stxp->multi_line ) + return; +#endif + + rct = stxp->rct; + if ( update && !xi_XinWindowPaintNeeds( stxp->win, &rct ) ) + return; + + tattrib = stxp->attrib; + /* if this field always has a border */ + if ( tattrib & XI_ATR_BORDER ) + { + do_border = TRUE; + border_color = stxp->enabled_color; + } + /* or if this field has a focus border, and the field has focus */ + if ( tattrib & XI_ATR_FOCUSBORDER ) + { + do_border = TRUE; + if ( stxp->has_focus ) + border_color = stxp->active_color; + else + { + border_color = stxp->parent_obj->itf->v.itf->back_color; + if ( !border_color ) + border_color = XI_COLOR_GRAY; + } + } + /* but if the field is not visible */ + if ( ( tattrib & XI_ATR_VISIBLE ) == 0 ) + do_border = FALSE; + + XinWindowClipSet( stxp->win, NULL ); + /* draw the border */ + if ( do_border ) + { + XinDrawTools dt; + + XinWindowDrawToolsNormalGet( &dt ); + dt.pen.fore_color = border_color; + dt.pen.width = 1; + dt.pen.pattern = XinPenSolid; + dt.brush.pattern = XinBrushHollow; + dt.brush.fore_color = XI_COLOR_WHITE; + dt.draw_mode = XinDrawModeCopy; + XinWindowDrawToolsSet( stxp->win, &dt ); + xi_draw_rect( stxp->win, &rct ); + } + + /* draw the 3d rectangle */ + if ( stxp->well || stxp->platform ) + { + XinRect r; + XinPoint p; + XinDrawTools dt; + + r = stxp->rct; + xi_inflate_rect( &r, -BORDER_WIDTH ); + xi_draw_3d_rect( stxp->win, &r, stxp->well, 2, stxp->hilight_color, + stxp->back_color, stxp->shadow_color ); + p.h = r.left + 1; + p.v = r.bottom - 2; + XinWindowDrawToolsNormalGet( &dt ); + dt.pen.fore_color = stxp->shadow_color; + if ( !dt.pen.fore_color ) + dt.pen.fore_color = xi_get_pref( XI_PREF_COLOR_CTRL ); + dt.pen.width = 1; + dt.pen.pattern = XinPenSolid; + dt.brush.pattern = XinBrushHollow; + dt.brush.fore_color = XI_COLOR_WHITE; + dt.draw_mode = XinDrawModeCopy; + XinWindowDrawToolsSet( stxp->win, &dt ); + xi_move_to( stxp->win, p ); + p.h = r.right - 1; + xi_draw_line( stxp->win, p ); + p.h -= 1; + xi_move_to( stxp->win, p ); + p.v = r.top; + xi_draw_line( stxp->win, p ); + } + else + { + XinRect r; + + r = stxp->rct; + xi_inflate_rect( &r, -BORDER_WIDTH ); + draw_back_rect( stxp, &r ); + } + + if ( stxp->xi_text ) + { + XinRect r; + + r = stxp->edit_rect; + xi_text_prect_set( stxp->xi_text, &r ); + xi_text_clip_set( stxp->xi_text, &r ); + + xi_text_draw( stxp->xi_text, 0L, 0L, update ); + } + if ( stxp->button && + (stxp->no_button_space == XinFlagTrue || + (stxp->no_button_space == XinFlagNotSet && + ( BOOLEAN ) xi_get_pref( XI_PREF_NO_BUTTON_SPACE ) ))) + xi_draw_field_button( stxp->parent_obj ); +} + +static void +stx_stop_edit( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + stxp->has_focus = FALSE; +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) && stxp->multi_line ) + { + XinWindow win; + + win = stxp->win; + xi_caret_off( win ); + xi_invalidate_rect( win, &stxp->rct ); + } + else +#endif + { + if ( stxp->enabled_color != stxp->active_color || + stxp->back_color != stxp->active_back_color ) + { + xi_text_color_fore_set( stxp->xi_text, stxp->enabled_color ); + xi_text_color_back_set( stxp->xi_text, stxp->back_color ); + } + xi_text_editing_stop( stxp->xi_text ); + stx_redraw( stx, FALSE ); + } +} + +STX +stx_create( XinWindow win, STX_DEF * stx_def, XinRect * field_button ) +{ + STX_DATA *stxp; + XinRect rct, + xt_rect; + int ascent, + descent, + leading, + font_height, + edit_height, + inflate; + XI_OBJ *itf; + + itf = xi_get_itf( win ); + XinWindowFontMap( win, stx_def->font ); + XinFontMetricsGet( stx_def->font, &leading, &ascent, &descent ); + font_height = ascent + leading + descent; + stxp = ( STX_DATA * ) xi_tree_malloc( sizeof( STX_DATA ), stx_def->parent ); + stxp->cid = stx_def->cid; + stxp->win = win; + stxp->attrib = stx_def->attrib; + + /* determine the outside rectangle for the edit control */ + edit_height = font_height + 2 * BORDER_WIDTH; + if ( stx_def->well || stx_def->platform ) + edit_height += 2 * DDD_RECT_DEPTH; + else + edit_height += 2 * BORDER_SPACE; + rct.left = stx_def->pnt.h; + rct.top = stx_def->pnt.v; + rct.right = stx_def->pnt.h + stx_def->pixel_width + 2 * BORDER_WIDTH; + if ( stx_def->well || stx_def->platform ) + rct.right += 2 * DDD_RECT_DEPTH; + else + rct.right += 2 * BORDER_SPACE; + rct.bottom = stx_def->pnt.v + edit_height; + stxp->rct = rct; + if ( stx_def->xi_rct.top || stx_def->xi_rct.left || + stx_def->xi_rct.bottom || stx_def->xi_rct.right ) + { + if ( ( stx_def->xi_rct.bottom - stx_def->xi_rct.top ) <= XI_FU_MULTIPLE ) + { + rct = stx_def->xi_rct; + xi_fu_to_pu( itf, ( XinPoint * ) & rct, 2 ); + rct.bottom = rct.top + edit_height; + stxp->rct = rct; + stxp->multi_line = FALSE; + } + else + { + rct = stx_def->xi_rct; + xi_fu_to_pu( xi_get_itf( win ), ( XinPoint * ) & rct, 2 ); + stxp->rct = rct; + stxp->multi_line = TRUE; + } + } + else + stxp->multi_line = FALSE; + + /* determine the actual boundary rect for the editing space. the calculation + * is the same regardless of whether it is XI_TEXT or TX_EDIT. */ + if ( stx_def->well || stx_def->platform ) + inflate = -( BORDER_WIDTH + DDD_RECT_DEPTH ); + else + inflate = -( BORDER_WIDTH + BORDER_SPACE ); + xt_rect = stxp->rct; + xi_inflate_rect( &xt_rect, inflate ); + if ( stx_def->button && + (stx_def->no_button_space == XinFlagTrue || + (stx_def->no_button_space == XinFlagNotSet && + ( BOOLEAN ) xi_get_pref( XI_PREF_NO_BUTTON_SPACE ) ))) + { + int delta; + + if ( stx_def->platform || stx_def->well ) + { + stx_def->button_rect.top = xt_rect.top; + stx_def->button_rect.bottom = xt_rect.bottom; + } + else + { + stx_def->button_rect.top = stxp->rct.top; + stx_def->button_rect.bottom = stxp->rct.bottom; + } + if (stx_def->button_width > 0) + delta = stx_def->button_width; + else + delta = ( ( stx_def->button_rect.bottom - stx_def->button_rect.top ) ); + if ( stx_def->button_on_left ) + { + if ( stx_def->platform || stx_def->well ) + { + stx_def->button_rect.left = xt_rect.left; + xt_rect.left += delta; + } + else + { + stx_def->button_rect.left = stxp->rct.left; + xt_rect.left = stxp->rct.left + delta; + } + stx_def->button_rect.right = xt_rect.left; + } + else + { + if ( stx_def->platform || stx_def->well ) + { + stx_def->button_rect.right = xt_rect.right; + xt_rect.right -= delta; + } + else + { + stx_def->button_rect.right = stxp->rct.right; + xt_rect.right = stxp->rct.right - delta; + } + stx_def->button_rect.left = xt_rect.right; + } + *field_button = stx_def->button_rect; + } + stxp->edit_rect = xt_rect; + + stxp->font = stx_def->font; + stxp->back_color = stx_def->back_color; + stxp->enabled_color = stx_def->enabled_color; + stxp->disabled_color = stx_def->disabled_color; + stxp->active_color = stx_def->active_color; + stxp->active_back_color = stx_def->active_back_color; + stxp->disabled_back_color = stx_def->disabled_back_color; + stxp->hilight_color = stx_def->hilight_color; + stxp->shadow_color = stx_def->shadow_color; + stxp->stx_cb = stx_def->stx_cb; + stxp->text_size = stx_def->text_size; + stxp->app_data = stx_def->app_data; + stxp->has_focus = FALSE; + stxp->well = stx_def->well; + stxp->platform = stx_def->platform; + stxp->auto_tab = stx_def->auto_tab; + stxp->scroll_bar = stx_def->scroll_bar; + stxp->cr_ok = stx_def->cr_ok; + stxp->var_len_text = stx_def->var_len_text; + stxp->parent_obj = stx_def->parent_obj; + stxp->button = stx_def->button; + stxp->button_on_left = stx_def->button_on_left; + stxp->button_rect = stx_def->button_rect; + stxp->no_button_space = stx_def->no_button_space; + stxp->button_width = stx_def->button_width; +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) && stxp->multi_line ) + { + unsigned attrib; + TXEDIT txt_edit; + XVT_FNTID xvt_font; + + attrib = TX_WRAP; + if ( stxp->attrib & XI_ATR_READONLY ) + attrib |= TX_READONLY; + attrib |= TX_AUTOHSCROLL | TX_AUTOVSCROLL; + stxp->txedit = BAD_TXEDIT; + xvt_font = XinFontXvtConvertBack( stx_def->font ); + txt_edit = xvt_tx_create( ( WINDOW ) win, ( RCT * ) & rct, attrib, + xvt_font, rct.right - rct.left - 4, INT_MAX ); + stxp->txedit = txt_edit; + xvt_tx_set_colors( txt_edit, stxp->enabled_color, + stxp->enabled_color, stxp->back_color ); + xvt_tx_add_par( txt_edit, 0, "" ); + + /* the following line is a hack for ms-windows */ + xi_caret_off( win ); + } + else +#endif + { + stxp->xi_text = xi_text_construct( stxp->win, + stxp->edit_rect.right - stxp->edit_rect.left, stxp->font, ( void * ) stxp, + stxp->multi_line, stxp->parent_obj->cid, TRUE ); + if ( stxp->attrib & XI_ATR_RJUST ) + xi_text_right_justify_set( stxp->xi_text, TRUE ); + if ( !( stxp->attrib & XI_ATR_VISIBLE ) ) + xi_text_visible_set( stxp->xi_text, FALSE ); + stx_update_colors( ( STX ) stxp ); + xi_text_parent_obj_set( stxp->xi_text, stx_def->parent_obj ); + xi_text_var_len_text_set( stxp->xi_text, stx_def->var_len_text ); + xi_text_buffer_size_set( stxp->xi_text, stxp->text_size ); + xi_text_min_buffer_size_set( stxp->xi_text, stxp->text_size ); + xi_text_scrollbar_set( stxp->xi_text, stxp->scroll_bar ); + xi_text_prect_set( stxp->xi_text, &stxp->edit_rect ); + xi_text_read_only_set( stxp->xi_text, ( stxp->attrib & XI_ATR_READONLY ) != 0 ); + xi_text_password_set( stxp->xi_text, ( stxp->attrib & XI_ATR_PASSWORD ) != 0 ); + xi_text_clip_set( stxp->xi_text, &stxp->edit_rect ); + xi_text_pix_width_and_text_set( stxp->xi_text, "", stxp->edit_rect.right - stxp->edit_rect.left, + TRUE ); + xi_text_cr_ok_set( stxp->xi_text, stxp->cr_ok ); + } + return ( ( STX ) ( long ) stxp ); +} + +void +stx_set_rect( XinWindow win, STX stx, XinRect *new_rect, XinRect *field_button ) +{ + STX_DATA *stxp; + XinRect rct, + xt_rect; + int ascent, + descent, + leading, + font_height, + edit_height, + inflate; + + XinWindowFontMap( win, xi_text_font_get( stx_xi_text_get( stx ) ) ); + XinFontMetricsGet( xi_text_font_get( stx_xi_text_get( stx ) ), + &leading, &ascent, &descent ); + font_height = ascent + leading + descent; + stxp = ( STX_DATA * ) stx; + + /* determine the outside rectangle for the edit control */ + edit_height = font_height + 2 * BORDER_WIDTH; + if ( stxp->well || stxp->platform ) + edit_height += 2 * DDD_RECT_DEPTH; + else + edit_height += 2 * BORDER_SPACE; + + if ( ( new_rect->bottom - new_rect->top ) <= XI_FU_MULTIPLE ) + { + rct = *new_rect; + rct.bottom = rct.top + edit_height; + stxp->rct = rct; + stxp->multi_line = FALSE; + } + else + { + stxp->rct = *new_rect; + stxp->multi_line = TRUE; + } + + /* determine the actual boundary rect for the editing space. the calculation + * is the same regardless of whether it is XI_TEXT or TX_EDIT. */ + if ( stxp->well || stxp->platform ) + inflate = -( BORDER_WIDTH + DDD_RECT_DEPTH ); + else + inflate = -( BORDER_WIDTH + BORDER_SPACE ); + xt_rect = stxp->rct; + xi_inflate_rect( &xt_rect, inflate ); + if ( stxp->button && + (stxp->no_button_space == XinFlagTrue || + (stxp->no_button_space == XinFlagNotSet && + ( BOOLEAN ) xi_get_pref( XI_PREF_NO_BUTTON_SPACE ) ))) + { + int delta; + + if ( stxp->platform || stxp->well ) + { + stxp->button_rect.top = xt_rect.top; + stxp->button_rect.bottom = xt_rect.bottom; + } + else + { + stxp->button_rect.top = stxp->rct.top; + stxp->button_rect.bottom = stxp->rct.bottom; + } + if (stxp->button_width > 0) + delta = stxp->button_width; + else + delta = ( ( stxp->button_rect.bottom - stxp->button_rect.top ) ); + if ( stxp->button_on_left ) + { + if ( stxp->platform || stxp->well ) + { + stxp->button_rect.left = xt_rect.left; + xt_rect.left += delta; + } + else + { + stxp->button_rect.left = stxp->rct.left; + xt_rect.left = stxp->rct.left + delta; + } + stxp->button_rect.right = xt_rect.left; + } + else + { + if ( stxp->platform || stxp->well ) + { + stxp->button_rect.right = xt_rect.right; + xt_rect.right -= delta; + } + else + { + stxp->button_rect.right = stxp->rct.right; + xt_rect.right = stxp->rct.right - delta; + } + stxp->button_rect.left = xt_rect.right; + } + *field_button = stxp->button_rect; + } + stxp->edit_rect = xt_rect; + + xi_text_prect_set( stxp->xi_text, &stxp->edit_rect ); +} + +void +stx_delete( STX stx, BOOLEAN destroy_font ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + { + if ( stxp->use_text_edit ) + { + xvt_tx_destroy( stxp->txedit ); + xi_invalidate_rect( stxp->win, &stxp->rct ); + } + } + else +#endif + { + if ( stxp->has_focus ) + stx_stop_edit( stx ); + if ( destroy_font ) + XinFontDestroy( stxp->font ); + xi_text_destruct( stxp->xi_text ); + xi_invalidate_rect( stxp->win, &stxp->rct ); + } + xi_tree_free( ( char * ) stx ); +} + +void +stx_destroy_font( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + XinFontDestroy( stxp->font ); +} + +static void +stx_start_edit( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + stxp->has_focus = TRUE; +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + { + xvt_tx_set_active( stxp->txedit ); + xi_invalidate_rect( stxp->win, &stxp->rct ); + } + else +#endif + { + if ( stxp->enabled_color != stxp->active_color || + stxp->back_color != stxp->active_back_color ) + { + xi_text_color_fore_set( stxp->xi_text, stxp->active_color ); + xi_text_color_back_set( stxp->xi_text, stxp->active_back_color ); + } + stx_redraw( stx, FALSE ); + xi_text_editing_start( stxp->xi_text ); + if ( stxp->have_mouse ) + { + if ( ( stxp->attrib & ( XI_ATR_AUTOSELECT | XI_ATR_READONLY ) ) == + ( XI_ATR_AUTOSELECT | XI_ATR_READONLY ) ) + xi_text_selection_set( stxp->xi_text, 0, SHRT_MAX ); + else if ( ( stxp->attrib & XI_ATR_AUTOSELECT ) && xi_get_pref( XI_PREF_AUTOSEL_ON_MOUSE ) ) + xi_text_selection_set( stxp->xi_text, 0, SHRT_MAX ); + } + else + { + if ( stxp->attrib & XI_ATR_AUTOSELECT ) + xi_text_selection_set( stxp->xi_text, 0, SHRT_MAX ); + else + if ( stxp->attrib & XI_AGA_ATR_AUTOEND ) + { + int len = strlen(stxp->xi_text->string); + xi_text_selection_set( stxp->xi_text, len, len ); + } + else + xi_text_selection_set( stxp->xi_text, 0, 0 ); + } + } +} + +void +stx_focus_set( long stx, BOOLEAN set ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + +/* verificare la correttezza + if ( set == stxp->has_focus ) + XinError( 30101, XinSeverityFatal, 0L ); +*/ + if ( set ) + { + XI_TEXT *cur_text = xi_text_focus_get( stxp->win ); + + if ( cur_text && xi_text_editing_is( cur_text ) ) + xi_text_editing_stop( cur_text ); + stx_start_edit( stx ); + } + else + stx_stop_edit( stx ); +} + +/* + do_stx_cb: handles the STX_CB_CHAR, STX_CB_CHANGE, STX_CB_FOCUS cases. +*/ +static BOOLEAN +do_stx_cb( STX stx, STX_CB_TYPE cb_reason, XinEvent * ep ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + STX_CB_DATA stx_cb_data; + + stx_cb_data.stx = stx; + stx_cb_data.cb_type = cb_reason; + stx_cb_data.cid = stxp->cid; + stx_cb_data.win = stxp->win; + if ( cb_reason == STX_CB_CHAR ) + { + stx_cb_data.v.chr.ch = ep->v.character.ch; + stx_cb_data.v.chr.shift = ep->v.character.shift; + stx_cb_data.v.chr.control = ep->v.character.control; + stx_cb_data.v.chr.alt = ep->v.character.alt; + stx_cb_data.v.chr.is_paste = FALSE; + stx_cb_data.v.chr.refused = FALSE; + } + else + stx_cb_data.v.refused = FALSE; + ( *stxp->stx_cb ) ( &stx_cb_data ); + + /* retval = FALSE if event refused */ + if ( cb_reason == STX_CB_CHAR ) + { + if ( !stx_cb_data.v.chr.refused ) + ep->v.character.ch = stx_cb_data.v.chr.ch; + return ( !stx_cb_data.v.chr.refused ); + } + else + return ( !stx_cb_data.v.refused ); +} + +/* +The parameter gaining_focus is here so that on an XinEventMouseDown, if the +field is gaining the focus, and XI_PREF_AUTOSEL_ON_MOUSE is TRUE, then +txt_event knows to select the entire field, not set an insertion point. +*/ +static BOOLEAN +send_txt_event( STX stx, XinEvent * ep, BOOLEAN gaining_focus ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + BOOLEAN retval; + +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + { + if ( ep->type != XinEventMenuCommand ) + retval = xi_xvt_tx_event( stxp->win, ep ); + if ( ep->type == XinEventMenuCommand && xi_get_pref( XI_PREF_MULTILINE_QUICK_PASTE ) ) + retval = xi_xvt_tx_event( stxp->win, ep ); + if ( retval ) + { + ( ( XI_OBJ * ) stxp->app_data )->itf->v.itf->chg_flag = TRUE; + do_stx_cb( stx, STX_CB_CHANGE, ep ); + } + } + else +#endif + { + BOOLEAN changed; + + retval = xi_text_event( stxp->xi_text, ep, gaining_focus, &changed ); + + if ( changed ) + { + ( ( XI_OBJ * ) stxp->app_data )->itf->v.itf->chg_flag = TRUE; + do_stx_cb( stx, STX_CB_CHANGE, ep ); + if ( stxp->auto_tab && ( int ) strlen( xi_text_get( stxp->xi_text ) ) + >= stxp->text_size - 1 ) + { + XinEvent ev; + + MEMCLEAR( ev ); + ev.type = XinEventCharacter; + ev.v.character.ch = '\t'; + xi_event( stxp->win, &ev ); + } + } + } + + return retval; +} + +/* +return TRUE if event used, FALSE if event not used. +*/ +BOOLEAN +stx_event( STX stx, XinEvent * ep ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + BOOLEAN use_event = TRUE; + BOOLEAN refused; + + switch ( ep->type ) + { + case XinEventResize: + use_event = FALSE; + break; + case XinEventTimer: + send_txt_event( stx, ep, FALSE ); + use_event = FALSE; + break; + case XinEventPaint: +#if 0 +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + { + if ( ( stxp->attrib & XI_ATR_VISIBLE ) != 0 ) + { + XinBrush cbrush; + XinRect r; + + if ( ep->type == XinEventPaint ) + draw_text_edit_border( stxp ); + cbrush.fore_color = stxp->back_color; + cbrush.pattern = XinBrushSolid; + XinWindowBrushSet( stxp->win, &cbrush ); + XinWindowPenSet( stxp->win, &hollow_cpen ); + r = stxp->rct; + if ( stxp->attrib & XI_ATR_BORDER || stxp->attrib & XI_ATR_FOCUSBORDER ) + xi_inflate_rect( &r, -1 ); + xi_inflate_rect( &r, -2 ); + xi_draw_rect( stxp->win, &r ); + xi_xvt_tx_event( stxp->win, ep ); + } + } + else +#endif +#endif + { + if ( ( stxp->attrib & XI_ATR_VISIBLE ) != 0 ) + stx_redraw( stx, TRUE ); + } + use_event = FALSE; + break; + case XinEventMouseDown: + case XinEventMouseDouble: + { + BOOLEAN gaining_focus = FALSE; + + /* check for focus acquisition */ + if ( xi_pt_in_rect( &stxp->rct, ep->v.mouse.where ) && + ( stxp->attrib & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) == + ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) + { + stxp->have_mouse = TRUE; + if ( !stxp->has_focus ) + { + if ( !do_stx_cb( stx, STX_CB_FOCUS, ep ) ) + { + stxp->have_mouse = FALSE; + break; + } + gaining_focus = TRUE; + } + /* the stx may have lost the focus, due to a field being disabled, in + * which case, stxp->xi_text == NULL */ + send_txt_event( stx, ep, gaining_focus ); + if ( stxp->xi_text ) + XinWindowMouseTrap( stxp->win, TRUE ); + if ( ep->type == XinEventMouseDouble ) + do_stx_cb( stx, STX_CB_DBL, ep ); + } + else + use_event = FALSE; + break; + } + case XinEventMouseUp: + if ( stxp->has_focus ) + { + send_txt_event( stx, ep, FALSE ); + XinWindowMouseRelease( ); + stxp->have_mouse = FALSE; + } + break; + case XinEventMouseMove: + { + unsigned long attrib; + XinRect r; + + if ( stxp->has_focus ) + send_txt_event( stx, ep, FALSE ); + attrib = stxp->attrib & ( XI_ATR_ENABLED | XI_ATR_VISIBLE ); + r = stxp->edit_rect; + +#if XIWS == XIWS_MAC || XIWS == XIWS_XM || XIWS == XIWS_WXGTK + if ( stxp->xi_text ) + xi_text_rect_get_adjusted( stxp->xi_text, &r ); +#endif + if ( ( attrib != ( XI_ATR_ENABLED | XI_ATR_VISIBLE ) ) || + ( !xi_pt_in_rect( &r, ep->v.mouse.where ) ) ) + use_event = FALSE; + break; + } + case XinEventCharacter: + { + int ch; + + ch = ep->v.character.ch; + if ( ch == '\t' || ch == XI_KEY_BTAB || ep->v.character.alt ) + return FALSE; + if ( stxp->multi_line ) + { + if ( ch >= ' ' || ch == XI_KEY_CLEAR || ch == XI_KEY_DEL || ch == '\b' ) + { + refused = do_stx_cb( stx, STX_CB_CHAR, ep ); + /* use_event = FALSE if event refused */ + if ( !refused ) + return FALSE; + } + } + else + { + if ( ( ch >= ' ' || ch == XI_KEY_CLEAR || ch == XI_KEY_DEL || + ch == '\b' ) && ch != XI_KEY_UP && ch != XI_KEY_DOWN ) + { + refused = do_stx_cb( stx, STX_CB_CHAR, ep ); + /* retval = FALSE if event refused */ + if ( !refused ) + return FALSE; + } + } + use_event = send_txt_event( stx, ep, FALSE ); + break; + } + case XinEventDestroy: + use_event = FALSE; + break; + case XinEventMenuCommand: + use_event = send_txt_event( stx, ep, FALSE ); + break; + default: + break; + } + return use_event; +} + +unsigned long +stx_get_attrib( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + return stxp->attrib; +} + +int +stx_get_cid( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + return stxp->cid; +} + +void +stx_get_sel( STX stx, int *c1, int *c2 ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) && stxp->multi_line ) + { + int accum_cnt; + T_PNUM par; + T_PNUM start_par, + end_par; + T_LNUM start_line, + end_line; + T_CNUM start_char, + end_char; + BOOLEAN ex; + TXEDIT txed = stxp->txedit; + + accum_cnt = 0; + xvt_tx_get_sel( txed, &start_par, &start_line, &start_char, + &end_par, &end_line, &end_char ); + ex = FALSE; + for ( par = 0; par <= start_par; par++ ) + { + T_LNUM nbr_lins, + lin; + + nbr_lins = xvt_tx_get_num_par_lines( txed, par ); + for ( lin = 0; lin < nbr_lins; lin++ ) + { + if ( par == start_par && lin == start_line ) + { + accum_cnt += start_char; + ex = TRUE; + break; + } + accum_cnt += xvt_tx_get_num_chars( txed, par, lin ); + } + if ( ex ) + break; + accum_cnt += 1; /* add eol at end of paragraph */ + } + *c1 = accum_cnt; + if ( start_par == end_par && start_line == end_line && + start_char == end_char ) + { + *c2 = accum_cnt; + return; + } + ex = FALSE; + for ( par = start_par; par <= end_par; par++ ) + { + T_LNUM nbr_lins, + lin; + + nbr_lins = xvt_tx_get_num_par_lines( txed, par ); + for ( lin = 0; lin < nbr_lins; lin++ ) + { + if ( par == end_par && lin == end_line ) + { + accum_cnt += end_char; + if ( par == start_par && lin == start_line ) + accum_cnt -= start_char; + ex = TRUE; + break; + } + accum_cnt += xvt_tx_get_num_chars( txed, par, lin ); + if ( par == start_par && lin == start_line ) + accum_cnt -= start_char; + } + if ( ex ) + break; + accum_cnt += 1; /* add eol at end of paragraph */ + } + *c2 = accum_cnt; + return; + } +#endif + if ( xi_text_editing_is( stxp->xi_text ) ) + xi_text_selection_get( stxp->xi_text, c1, c2 ); + else + *c1 = *c2 = 0; +} + +XinRect * +stx_get_rect( STX stx, XinRect * rctp ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + *rctp = stxp->rct; + return rctp; +} + +#ifdef XI_USE_TX_SUPPORT +static void +tx_get_text( TXEDIT tx, char *string, int string_len ) +{ + char *s; + int slen, + cnt, + nbr_pars; + unsigned len; + + slen = 0; + s = NULL; + nbr_pars = xvt_tx_get_num_pars( tx ); + for ( cnt = 0; cnt < nbr_pars; ++cnt ) + { + int nbr_lines, + cnt2; + + nbr_lines = xvt_tx_get_num_par_lines( tx, ( short ) cnt ); + for ( cnt2 = 0; cnt2 < nbr_lines; ++cnt2 ) + { + char *str; + int old_len; + + xvt_tx_get_line( tx, ( short ) cnt, A_LOCK, ( short ) cnt2, NULL ); + str = xvt_tx_get_line( tx, ( short ) cnt, A_GET, ( short ) cnt2, &len ); + old_len = slen; + slen = slen + len; + if ( s ) + s = ( char * ) xi_tree_realloc( s, slen + 2 ); + else + s = ( char * ) xi_tree_malloc( slen + 2, NULL ); + + gstrncpy( &s[old_len], str, len ); + } + slen++; +#if XIWS == XIWS_MAC + s[slen - 1] = '\r'; +#else + s[slen - 1] = '\n'; +#endif + } + if ( !slen ) + string[0] = '\0'; + else + { + s[slen - 1] = '\0'; + gstrncpy( string, s, string_len ); + string[string_len - 1] = '\0'; + xi_tree_free( s ); + } +} + +static int +tx_get_len( TXEDIT tx ) +{ + int nbr_pars, + cnt, + charcnt; + + charcnt = 0; + nbr_pars = xvt_tx_get_num_pars( tx ); + for ( cnt = 0; cnt < nbr_pars; ++cnt ) + { + int nbr_lines, + cnt2; + + nbr_lines = xvt_tx_get_num_par_lines( tx, ( short ) cnt ); + for ( cnt2 = 0; cnt2 < nbr_lines; ++cnt2 ) + charcnt += ( xvt_tx_get_num_chars( tx, ( short ) cnt, ( short ) cnt2 ) + 1 ); + } + return charcnt; +} + +#endif + +char * +stx_get_text( STX stx, char *s, int len ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + char *b; + +#ifdef XI_USE_TX_SUPPORT + if ( stxp->multi_line && xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + { + TXEDIT txed = stxp->txedit; + + if ( s ) + { + tx_get_text( txed, s, len ); + b = s; + } + else + { + int len; + + len = tx_get_len( txed ); + if ( stxp->buf ) + stxp->buf = ( char * ) xi_tree_realloc( stxp->buf, len ); + else + stxp->buf = ( char * ) xi_tree_malloc( len, NULL ); + tx_get_text( txed, stxp->buf, len ); + b = stxp->buf; + } + } + else +#endif + { + b = xi_text_get( stxp->xi_text ); + } + if ( s ) + tstrncpy( s, b, len ); + return b; +} + +void +stx_set_bufsize( STX stx, short size ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + xi_text_buffer_size_set( stxp->xi_text, size ); + stxp->text_size = size; +} + +void +stx_set_attrib( STX stx, unsigned long attrib ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + unsigned long do_redraw; + +#ifdef XI_USE_TX_SUPPORT + if ( stxp->multi_line && xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + { + TXEDIT txed = stxp->txedit; + + if ( attrib & XI_ATR_VISIBLE ) + { + if ( !( stxp->attrib & XI_ATR_VISIBLE ) ) + xvt_tx_resume( txed ); + } + else + { + if ( stxp->attrib & XI_ATR_VISIBLE ) + xvt_tx_suspend( txed ); + } + } +#endif + + do_redraw = ( ( stxp->attrib ^ attrib ) & STX_REDRAW_ATR ); + stxp->attrib = attrib; + if ( attrib & XI_ATR_ENABLED ) + { + xi_text_color_fore_set( stxp->xi_text, stxp->enabled_color ); + xi_text_color_back_set( stxp->xi_text, stxp->back_color ); + } + else + { + xi_text_color_fore_set( stxp->xi_text, stxp->disabled_color ); + xi_text_color_back_set( stxp->xi_text, stxp->disabled_back_color ); + } + xi_text_right_justify_set( stxp->xi_text, (BOOLEAN)( ( stxp->attrib & XI_ATR_RJUST ) != 0 ) ); + xi_text_read_only_set( stxp->xi_text, ( stxp->attrib & XI_ATR_READONLY ) != 0 ); + xi_text_password_set( stxp->xi_text, ( stxp->attrib & XI_ATR_PASSWORD ) != 0 ); + xi_text_visible_set( stxp->xi_text, ( BOOLEAN ) ( ( stxp->attrib & XI_ATR_VISIBLE ) != 0 ) ); + if ( do_redraw ) + xi_invalidate_rect( stxp->win, &( stxp->rct ) ); +} + +void +stx_set_focus( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + if ( XinWindowFocusGet( ) != stxp->win ) + { + XinWindowFocusSet( stxp->win ); + } + if ( !stxp->has_focus ) + stx_start_edit( stx ); +} + +void +stx_set_pos( STX stx, XinPoint p ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + int dh, + dv, + inflate; + XinRect r; + + dh = p.h - stxp->rct.left; + dv = p.v - stxp->rct.top; + + stxp->rct.top += dv; + stxp->rct.left += dh; + stxp->rct.bottom += dv; + stxp->rct.right += dh; + /* determine the actual boundary rect for the editing space. the calculation + * is the same regardless of whether it is XI_TEXT or TX_EDIT. */ + if ( stxp->well || stxp->platform ) + inflate = -( BORDER_WIDTH + DDD_RECT_DEPTH ); + else + inflate = -( BORDER_WIDTH + BORDER_SPACE ); + r = stxp->rct; + xi_inflate_rect( &r, inflate ); + if ( stxp->button && + (stxp->no_button_space == XinFlagTrue || + (stxp->no_button_space == XinFlagNotSet && + ( BOOLEAN ) xi_get_pref( XI_PREF_NO_BUTTON_SPACE ) ))) + { + if ( stxp->button_on_left ) + r.left += ( stxp->button_rect.right - stxp->button_rect.left ); + else + r.right -= ( stxp->button_rect.right - stxp->button_rect.left ); + } + stxp->edit_rect = r; + xi_text_prect_set( stxp->xi_text, &r ); +} + +void +stx_set_sel( STX stx, int c1, int c2 ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + +#ifdef XI_USE_TX_SUPPORT + if ( stxp->multi_line && xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + { + int accum_cnt, + selidx; + int sel[2]; + T_PNUM parsel[2], + par, + nbr_pars; + T_LNUM linsel[2], + lin, + nbr_lins; + T_CNUM chrsel[2], + nbr_chrs; + TXEDIT txed = stxp->txedit; + + accum_cnt = 0; + selidx = 0; + sel[0] = c1; + sel[1] = c2; + nbr_pars = xvt_tx_get_num_pars( txed ); + for ( par = 0; par < nbr_pars; par++ ) + { + nbr_lins = xvt_tx_get_num_par_lines( txed, par ); + for ( lin = 0; lin < nbr_lins; lin++ ) + { + nbr_chrs = xvt_tx_get_num_chars( txed, par, lin ); + while ( ( int ) ( accum_cnt + nbr_chrs ) >= sel[selidx] ) + { + parsel[selidx] = par; + linsel[selidx] = lin; + chrsel[selidx] = sel[selidx] - accum_cnt; + selidx++; + if ( selidx >= 2 ) + goto set_sel; + } + accum_cnt += nbr_chrs; + } + accum_cnt += 1; /* add eol at end of paragraph */ + } + while ( selidx < 2 ) + { + parsel[selidx] = nbr_pars - 1; + linsel[selidx] = nbr_lins - 1; + chrsel[selidx] = nbr_chrs - 1; + if ( selidx == 1 ) + chrsel[selidx] = nbr_chrs; + selidx++; + } +set_sel: + xvt_tx_set_sel( txed, parsel[0], linsel[0], chrsel[0], + parsel[1], linsel[1], chrsel[1] ); + return; + } +#endif + if ( !stxp->has_focus ) + stx_start_edit( stx ); + xi_text_selection_set( stxp->xi_text, c1, c2 ); +} + +#ifdef XI_USE_TX_SUPPORT +static void +do_tx_add_par( TXEDIT tx, int limit, char *text ) +{ + char *s, + *bp, + *ep; + int cnt, + nbr_pars; + + nbr_pars = xvt_tx_get_num_pars( tx ); + xvt_tx_suspend( tx ); + for ( cnt = 0; cnt < nbr_pars; ++cnt ) + xvt_tx_rem_par( tx, 0 ); + s = ( char * ) xi_tree_malloc( limit + 1, NULL ); + bp = text; + if ( text[0] == '\0' ) + { + xvt_tx_add_par( tx, ( unsigned short ) USHRT_MAX, s ); + xvt_tx_resume( tx ); + xi_tree_free( s ); + return; + } + while ( TRUE ) + { + int cnt, + min_cnt; + + if ( *bp == '\0' ) + break; + ep = bp; + cnt = 0; + while ( *ep != '\r' && *ep != '\n' && *ep != '\0' ) + { + ++ep; + ++cnt; + } + min_cnt = min( limit, cnt ); + gstrncpy( s, bp, min_cnt ); + s[min_cnt] = '\0'; + xvt_tx_add_par( tx, ( unsigned short ) USHRT_MAX, s ); + if ( *ep == '\0' ) + break; + bp = ep + 1; + } + xvt_tx_resume( tx ); + xi_tree_free( s ); +} + +#endif + +void +stx_set_text( STX stx, const char *s ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + +#ifdef XI_USE_TX_SUPPORT + if ( stxp->multi_line && xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + { + TXEDIT txed = stxp->txedit; + + do_tx_add_par( txed, stxp->text_size, s ); + xvt_tx_set_sel( txed, 0, 0, 0, 0, 0, 0 ); + } + else +#endif + { + xi_text_set( stxp->xi_text, s ); + + if ( ( stxp->attrib & XI_ATR_VISIBLE ) != 0 + && !xi_half_baked( stxp->win ) ) + stx_redraw( stx, FALSE ); + } +} + +void +stx_set_app_data( STX stx, long data ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + stxp->app_data = data; +} + +long +stx_get_app_data( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + return stxp->app_data; +} + +XI_TEXT * +stx_xi_text_get( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + return stxp->xi_text; +} + +#ifdef XI_USE_TX_SUPPORT +BOOLEAN +xi_is_txedit( XI_OBJ * xi_obj ) +{ + if ( stx_get_txedit( xi_obj->v.field->stx ) == BAD_TXEDIT ) + return FALSE; + return TRUE; +} + +void +xi_tx_edit_move( XI_OBJ * xi_obj ) +{ + TXEDIT text_edit; + XI_ITF_DATA *itf_data; + XinRect rect; + XinRect new_rect; + XinWindow window; + STX_DATA *stxp; + + if ( !xi_is_txedit( xi_obj ) ) + return; + text_edit = stx_get_txedit( xi_obj->v.field->stx ); + ( WINDOW ) window = xvt_tx_get_win( text_edit ); + itf_data = xi_obj->itf->v.itf; + xvt_tx_get_rect( text_edit, ( RCT * ) & rect ); + stxp = ( STX_DATA * ) xi_obj->v.field->stx; + new_rect = stxp->edit_rect; + xi_offset_rect( &new_rect, itf_data->delta_x, itf_data->delta_y ); + xvt_tx_move( text_edit, ( RCT * ) & new_rect ); + xi_inflate_rect( &new_rect, 1 ); + xi_invalidate_rect( window, &new_rect ); + xi_inflate_rect( &rect, 1 ); + xi_invalidate_rect( window, &rect ); +} + +BOOLEAN +xi_xvt_tx_event( XinWindow win, XinEvent * ep ) +{ + EVENT e; + + if ( convert_event_back( &e, ep ) ) + return xvt_tx_process_event( ( WINDOW ) win, &e ); + return FALSE; +} + +static SCROLL_CONTROL +convert_what_back( XinScrollBarAction scroll_control ) +{ + switch ( scroll_control ) + { +case XinScrollBarActionLineUp: + return SC_LINE_UP; + case XinScrollBarActionLineDown: + return SC_LINE_DOWN; + case XinScrollBarActionPageUp: + return SC_PAGE_UP; + case XinScrollBarActionPageDown: + return SC_PAGE_DOWN; + case XinScrollBarActionThumb: + return SC_THUMB; + case XinScrollBarActionThumbTrack: + return SC_THUMBTRACK; + } + return SC_LINE_UP; +} + +static BOOLEAN +convert_event_back( EVENT * ep, XinEvent * xiep ) +{ + BOOLEAN retval = TRUE; + + switch ( xiep->type ) + { + case XinEventCreate: + ep->type = E_CREATE; + break; + case XinEventDestroy: + ep->type = E_DESTROY; + break; + case XinEventFocus: + ep->type = E_FOCUS; + ep->v.active = xiep->v.focus.active; + break; + case XinEventResize: + ep->type = E_SIZE; + ep->v.size.width = xiep->v.resize.width; + ep->v.size.height = xiep->v.resize.height; + break; + case XinEventPaint: + ep->type = E_UPDATE; + ep->v.update.rct = *( RCT * ) & xiep->v.paint.rect; + break; + case XinEventCloseButton: + ep->type = E_CLOSE; + break; + case XinEventMouseDown: + ep->type = E_MOUSE_DOWN; + ep->v.mouse.where.v = xiep->v.mouse.where.v; + ep->v.mouse.where.h = xiep->v.mouse.where.h; + ep->v.mouse.shift = xiep->v.mouse.shift; + ep->v.mouse.control = xiep->v.mouse.control; + ep->v.mouse.button = xiep->v.mouse.button; + break; + case XinEventMouseUp: + ep->type = E_MOUSE_UP; + ep->v.mouse.where.v = xiep->v.mouse.where.v; + ep->v.mouse.where.h = xiep->v.mouse.where.h; + ep->v.mouse.shift = xiep->v.mouse.shift; + ep->v.mouse.control = xiep->v.mouse.control; + ep->v.mouse.button = xiep->v.mouse.button; + break; + case XinEventMouseMove: + ep->type = E_MOUSE_MOVE; + ep->v.mouse.where.v = xiep->v.mouse.where.v; + ep->v.mouse.where.h = xiep->v.mouse.where.h; + ep->v.mouse.shift = xiep->v.mouse.shift; + ep->v.mouse.control = xiep->v.mouse.control; + ep->v.mouse.button = xiep->v.mouse.button; + break; + case XinEventMouseDouble: + ep->type = XinEventMouseDouble; + ep->v.mouse.where.v = xiep->v.mouse.where.v; + ep->v.mouse.where.h = xiep->v.mouse.where.h; + ep->v.mouse.shift = xiep->v.mouse.shift; + ep->v.mouse.control = xiep->v.mouse.control; + ep->v.mouse.button = xiep->v.mouse.button; + break; + case XinEventCharacter: + ep->type = E_CHAR; + ep->v.chr.ch = xiep->v.character.ch; +#if XIWS == XIWS_WM + /* TODO ep->v.chr.shift and ep->v.chr.control are not set properly for + * XVT/CH */ + xiep->v.character.shift = FALSE; + xiep->v.character.control = FALSE; +#else + ep->v.chr.shift = xiep->v.character.shift; + ep->v.chr.control = xiep->v.character.control; +#endif + break; + case XinEventHScroll: + ep->type = E_HSCROLL; + ep->v.scroll.pos = xiep->v.scroll.position; + ep->v.scroll.what = convert_what_back( xiep->v.scroll.action ); + break; + case XinEventVScroll: + ep->type = E_VSCROLL; + ep->v.scroll.pos = xiep->v.scroll.position; + ep->v.scroll.what = convert_what_back( xiep->v.scroll.action ); + break; + case XinEventMenuCommand: + ep->type = E_COMMAND; + ep->v.cmd.tag = xiep->v.menu_command.tag; + ep->v.cmd.shift = xiep->v.menu_command.shift; + ep->v.cmd.control = xiep->v.menu_command.control; + break; + case XinEventFont: + ep->type = E_FONT; + ep->v.font.font_id = XinFontXvtConvertBack( xiep->v.font.font ); + break; + case XinEventControl: + ep->type = E_CONTROL; + ep->v.ctl.id = xiep->v.control.control_id; + switch ( xiep->v.control.ctrl_info.type ) + { + /* non-xvt versions do not need to support buttons, radio buttons, + * and check boxes */ + case XinWindowTypeButton: + ep->v.ctl.ci.type = WC_PUSHBUTTON; + break; + case XinWindowTypeRadioButton: + ep->v.ctl.ci.type = WC_RADIOBUTTON; + break; + case XinWindowTypeCheckBox: + ep->v.ctl.ci.type = WC_CHECKBOX; + break; + case XinWindowTypeVerticalScrollBar: + ep->v.ctl.ci.win = ( WINDOW ) xiep->v.control.ctrl_info.win; + ep->v.ctl.ci.type = WC_HSCROLL; + ep->v.ctl.ci.v.scroll.what = convert_what_back( xiep->v.control.ctrl_info.v.scroll.action ); + ep->v.ctl.ci.v.scroll.pos = xiep->v.control.ctrl_info.v.scroll.position; + break; + case XinWindowTypeHorizontalScrollBar: + ep->v.ctl.ci.win = ( WINDOW ) xiep->v.control.ctrl_info.win; + ep->v.ctl.ci.type = WC_HSCROLL; + ep->v.ctl.ci.v.scroll.what = convert_what_back( xiep->v.control.ctrl_info.v.scroll.action ); + ep->v.ctl.ci.v.scroll.pos = xiep->v.control.ctrl_info.v.scroll.position; + break; + } + break; + case XinEventTimer: + ep->type = E_TIMER; + ep->v.timer.id = xiep->v.timer.id; + break; + case XinEventQuit: + ep->type = E_QUIT; + ep->v.query = xiep->v.quit.query; + break; + case XinEventHelp: + ep->type = E_HELP; + ep->v.help.obj = ( WINDOW ) xiep->v.help.obj; + ep->v.help.tag = xiep->v.help.tag; + ep->v.help.tid = xiep->v.help.topic_id; + break; + case XinEventUser: + xiep->type = E_USER; + ep->v.user.id = xiep->v.user.id; + ep->v.user.ptr = xiep->v.user.ptr; + break; + default: + retval = FALSE; + break; + } + return retval; +} + +#if 0 +/*--------------------------------------------------------------------- +function: draw_text_edit_border +stxptr: +process: +---------------------------------------------------------------------*/ +static void +draw_text_edit_border( STX_DATA * stxp ) +{ + XinRect rct; + + XinWindowDrawModeSet( stxptr->win, XinDrawModeCopy ); + XinWindowPenSet( stxptr->win, &black_cpen ); + XinWindowBrushSet( stxptr->win, &hollow_cbrush ); + rct = stxptr->rct; + if ( stxptr->attrib & XI_ATR_BORDER ) + { + xi_draw_rect( stxptr->win, &rct ); + xi_inflate_rect( &rct, -1 ); + } + else + { + if ( stxptr->attrib & XI_ATR_FOCUSBORDER ) + { + COLOR pen_color; + XinPen cpen; + + if ( stxptr->has_focus ) + { + pen_color = XI_COLOR_BLACK; + } + else + { + static XI_OBJ *itf; + COLOR back_color; + + itf = xi_get_itf( stxptr->win ); + back_color = itf->v.itf->back_color; + if ( back_color ) + pen_color = back_color; + else + pen_color = xi_get_pref( XI_PREF_COLOR_CTRL ); + } + cpen.fore_color = pen_color; + cpen.pattern = XinBrushSolid; + cpen.width = 1; + XinWindowPenSet( stxptr->win, &cpen ); + xi_draw_rect( stxptr->win, &rct ); + xi_inflate_rect( &rct, -1 ); + } + } + if ( ( ( BOOLEAN ) xi_get_pref( XI_PREF_3D_LOOK ) == FALSE ) + || ( ( stxptr->well == FALSE ) && ( stxptr->platform == FALSE ) ) ) + return; + xi_draw_3d_rect( stxptr->win, &rct, stxptr->well, 1, 0L, 0L, 0L ); +} + +#endif + +static TXEDIT +stx_get_txedit( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + return stxp->txedit; +} + +#endif + +BOOLEAN +stx_cr_is_ok( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + + return stxp->cr_ok; +} + +void +stx_update_colors( STX stx ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + +#ifdef XI_USE_TX_SUPPORT + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) && stxp->multi_line ) + xvt_tx_set_colors( stxp->txedit, stxp->enabled_color, + stxp->enabled_color, stxp->back_color ); + else +#endif + { + if ( stxp->has_focus ) + { + xi_text_color_fore_set( stxp->xi_text, stxp->active_color ); + xi_text_color_back_set( stxp->xi_text, stxp->active_back_color ); + } + else if ( stxp->attrib & XI_ATR_ENABLED ) + { + xi_text_color_fore_set( stxp->xi_text, stxp->enabled_color ); + xi_text_color_back_set( stxp->xi_text, stxp->back_color ); + } + else + { + xi_text_color_fore_set( stxp->xi_text, stxp->disabled_color ); + xi_text_color_back_set( stxp->xi_text, stxp->disabled_back_color ); + } + } +} + +void +stx_set_font( STX stx, XinFont* font ) +{ + STX_DATA *stxp = ( STX_DATA * ) stx; + XinFont* font_copy; + + XinFontCopy( &font_copy, font ); + + if ( stxp->xi_text != NULL ) + xi_text_font_set( stxp->xi_text, font_copy ); + XinFontDestroy( stxp->font ); + stxp->font = font_copy; +} diff --git a/src/xi01/xistx.h b/src/xi01/xistx.h new file mode 100644 index 000000000..dc5cf4dfe --- /dev/null +++ b/src/xi01/xistx.h @@ -0,0 +1,157 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define NULL_STX (STX)0 + +typedef enum +{ + STX_CB_CHAR, + STX_CB_CHANGE, + STX_CB_DBL, + STX_CB_FOCUS +} + +STX_CB_TYPE; + +typedef struct _stx_cb_data +{ + STX stx; + STX_CB_TYPE cb_type; + int cid; + XinWindow win; + union + { + /* nothing for change notify */ + BOOLEAN refused; + struct + { + int ch; + BOOLEAN shift; + BOOLEAN control; + BOOLEAN alt; + BOOLEAN is_paste; + BOOLEAN refused; + } chr; + } v; +} STX_CB_DATA; + +typedef void ( *STX_CB ) ( STX_CB_DATA * stx_cb_data ); + +typedef struct _stx_def +{ + int cid; + XinPoint pnt; + short pixel_width; + short pix_char_width; + unsigned long attrib; + short text_size; + XinFont *font; + XinColor back_color; + XinColor enabled_color; /* but inactive */ + XinColor disabled_color; + XinColor active_color; + XinColor active_back_color; + XinColor disabled_back_color; + XinColor hilight_color; /* for well and platform fields */ + XinColor shadow_color; /* for well and platform fields */ + XinRect xi_rct; + STX_CB stx_cb; + long app_data; + char *parent; + BOOLEAN well; + BOOLEAN platform; + BOOLEAN auto_tab; + BOOLEAN scroll_bar; + BOOLEAN cr_ok; + BOOLEAN var_len_text; + XI_OBJ *parent_obj; + BOOLEAN button; + BOOLEAN button_on_left; + XinRect button_rect; + XinFlag no_button_space; + int button_width; +} STX_DEF; + +typedef struct _stx_data +{ + int cid; + XinWindow win; + XinRect rct; + XinRect edit_rect; + unsigned long attrib; + short pixel_width; + short pix_baseline; + XinFont *font; + XinColor back_color; + XinColor enabled_color; /* but inactive */ + XinColor disabled_color; + XinColor disabled_back_color; + XinColor active_color; + XinColor active_back_color; + XinColor hilight_color; /* for well and platform fields */ + XinColor shadow_color; /* for well and platform fields */ + STX_CB stx_cb; + short text_size; + long app_data; + BOOLEAN have_mouse; + XI_TEXT *xi_text; + BOOLEAN multi_line; + BOOLEAN well; + BOOLEAN platform; + BOOLEAN auto_tab; + BOOLEAN scroll_bar; + BOOLEAN cr_ok; + BOOLEAN var_len_text; + char *buf; + BOOLEAN has_focus; + XI_OBJ *parent_obj; + BOOLEAN button; + BOOLEAN button_on_left; + XinRect button_rect; + XinFlag no_button_space; + int button_width; +#ifdef XI_USE_TX_SUPPORT + BOOLEAN use_text_edit; + long txedit; +#endif +} STX_DATA; + +#define STX_LOSE_FOCUS NULL_STX + +STX stx_create( XinWindow win, STX_DEF * stx_def, XinRect *field_button ); +void stx_delete( STX stx, BOOLEAN destroy_font ); +void stx_destroy_font( STX stx ); +BOOLEAN stx_event( STX stx, XinEvent * ep ); +void stx_focus_set( long stx, BOOLEAN set ); +unsigned long stx_get_attrib( STX stx ); +int stx_get_cid( STX stx ); +long stx_get_app_data( STX stx ); +void stx_get_sel( STX stx, int *c1, int *c2 ); +XinRect *stx_get_rect( STX stx, XinRect * rct ); +XinRect *stx_get_inside_rect( STX stx, XinRect * rect ); +char *stx_get_text( STX stx, char *s, int len ); +void stx_set_app_data( STX stx, long data ); +void stx_set_attrib( STX stx, unsigned long attrib ); +void stx_set_bufsize( STX stx, short size ); +void stx_set_focus( STX stx ); +void stx_set_pos( STX stx, XinPoint p ); +void stx_set_rect( XinWindow win, STX stx, XinRect *new_rect, XinRect *field_button ); +void stx_set_sel( STX stx, int c1, int c2 ); +void stx_set_text( STX stx, const char *s ); +XI_TEXT *stx_xi_text_get( STX stx ); +BOOLEAN stx_cr_is_ok( STX stx ); +void stx_update_colors( STX stx ); +void stx_set_font( STX stx, XinFont* font ); + +#ifdef XI_USE_TX_SUPPORT +BOOLEAN xi_is_txedit( XI_OBJ * xi_obj ); +BOOLEAN xi_xvt_tx_event( XinWindow win, XinEvent * ep ); +void xi_tx_edit_move( XI_OBJ * xi_obj ); + +#endif diff --git a/src/xi01/xitext.c b/src/xi01/xitext.c new file mode 100644 index 000000000..acba440f6 --- /dev/null +++ b/src/xi01/xitext.c @@ -0,0 +1,3390 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +/* {[( */ + +#define XI_INTERNAL +#include "xi.h" +#include "xitext.h" +#include "xilm.h" +#include "xilmst.h" +#include "xiutils.h" +#include "xistx.h" +#include + +#define is_word_char(ch) (ch != ' ' && ch != '\n') +#define SB_DELTA 3 +#define GRAN 32 +#define NEW_LEN( a ) (((((a) - 1 ) / GRAN ) + 1 ) * GRAN) + +/* +each XI_TEXT can be in an editing state, or a display only state. at times, +other modules need to request the state of the wrap. an instance is when the +lm or stx modules needs to set state of insertion points. + +more than one XI_TEXT can be in an editing state. an example of this is where +more than one window contain controls using XI_TEXT, each window has a control +that has focus within that window. + +when other modules need to interact with an XI_TEXT, such as setting the +selection, they need to inquire of the XI_TEXT if it is currently in an editing +state. there is no provision, and results are undefined, if another module +calls functions, or uses macros that are only valid for an XI_TEXT that is in +the editing state. + +save_text contains a pointer to a copy of an XI_TEXT. this is used to +save the state of an XI_TEXT before modifying when editing. this allows +us to optimize drawing after any editing action. + +note for the programmer maintaining this module: save_text must never be +assumed to contain any allocated data in between calls to this module. in +other words, any function that calls save_text_state must call +free_save_text_state before returning. + +calls to this module for a particular editing XI_TEXT may be interspersed with +other calls for another editing XI_TEXT. don't assume any state in this module +beyond the scope of one of the calls into the module. +*/ + +static XI_TEXT *save_text = NULL; +static void calc_delta_y( XI_TEXT * text ); +static void save_text_state( XI_TEXT * text ); +static void display_if_necessary( XI_TEXT * text, BOOLEAN recalc_delta_y ); +static void xi_text_caret_off( XI_TEXT * text ); +static void xi_text_caret_on( XI_TEXT * text ); +static void calc_delta_x( XI_TEXT * text ); +static void xi_text_hit_test( XI_TEXT * text, XinEvent * ep, int *ip ); + +/* +sets range, position, and proportion of the scroll bar. only called if +there is a scroll bar. +*/ +static void +xi_text_sb_set( XI_TEXT * text ) +{ + if ( xi_itf_in_event_destroy( text->itf ) ) + return; + if ( text->nbr_lines == 0 ) + { + XinScrollBarSet( text->sb_win, XinScrollBarTypeEither, 0, 1000, 0, 0 ); + } + else + { + double prop, + pos; + + prop = ( double ) text->max_lines_to_draw / ( double ) text->nbr_lines * 1000; + if ( prop > 1000 ) + prop = 1000; + pos = ( double ) text->delta_y / ( double ) text->nbr_lines * 1000; + XinScrollBarSet( text->sb_win, XinScrollBarTypeEither, 0, 1000, ( int ) prop, ( int ) pos ); + } +} + +/* +the process of wrapping text consists of breaking the string into segments. +this is the function that adds a segment to the line_breaks data structure. +(the line_breaks data structure contains the segments of wrapped text. +only called by xi_text_wrap_internal, and only if multi-line. +*/ +static void +add_seg( XI_TEXT * text, int seg_starting_pos ) +{ + XI_TEXT_LINE_BREAK *lb; + + ++text->nbr_lines; + if ( text->line_breaks ) + text->line_breaks = ( XI_TEXT_LINE_BREAK * ) xi_tree_realloc( text->line_breaks, + sizeof( XI_TEXT_LINE_BREAK ) * text->nbr_lines ); + else + text->line_breaks = ( XI_TEXT_LINE_BREAK * ) xi_tree_malloc( sizeof( XI_TEXT_LINE_BREAK ) * text->nbr_lines, + text ); + lb = &text->line_breaks[text->nbr_lines - 1]; + lb->line_break = seg_starting_pos; + lb->ip1 = lb->ip2 = -1; + lb->active_ip = -2; +} + +/* +creates an xi_text. initially, the xi_text is not editing text. to start +editing text, xi_text_editing_start must be called. + +win is the window into which the xi_text will be placed. + +pix_width is the physical pixel width. + +font is the desired font for the xi_text. + +parent is a parent pointer for xi_tree memory. the XI_TEXT is allocated with + this as its parent. + +if multi_line is true, the xi_text is a multi_line edit control. if false, + the xi_text is a single line edit control. +*/ + +XI_TEXT * +xi_text_construct( XinWindow win, int pix_width, XinFont * font, + void *parent, BOOLEAN multi_line, int cid, + BOOLEAN scrollbar_always_visible ) +{ + XI_TEXT *text; + + text = xi_tree_malloc( sizeof( XI_TEXT ), parent ); + text->win = win; + text->itf = xi_get_itf( win ); + text->font = font; + text->pix_width = pix_width; + text->multi_line = multi_line; + text->cid = cid; + text->scrollbar_always_visible = scrollbar_always_visible; + text->sb_win = XI_NULL_WINDOW; + text->delta_y = 0; + text->delta_x = 0; + text->editing = FALSE; + text->visible = TRUE; + return text; +} + +/* +this function does the actual wrapping of text. it is only used for a +multi_line edit control. +*/ +static void +xi_text_wrap_internal( XI_TEXT * text ) +{ + int char_width; + int cur_seg, + cur_seg_starting_pos, + avg_line_len, + seg_len; + XinFont *font; + int internal_pix_width = text->internal_pix_width; + char *string = text->string; + + if ( ! string ) + return; + font = text->font; + if ( text->line_breaks ) + { + xi_tree_free( text->line_breaks ); + text->line_breaks = NULL; + } + text->nbr_lines = 0; + xi_get_font_metrics_font( font, &text->leading, &text->ascent, &text->descent, &char_width ); + text->font_height = text->ascent + text->descent + text->leading; + avg_line_len = internal_pix_width / char_width; + if ( avg_line_len == 0 ) + avg_line_len = 1; + cur_seg_starting_pos = 0; + cur_seg = 0; + + /* find all segments in text */ + while ( string[ cur_seg_starting_pos ] != '\0' ) + { + int this_seg_len, + possible_word_break, + cur_seg_len, + word_break, + cnt; + BOOLEAN continue_loop; + + cur_seg_len = strlen( &string[cur_seg_starting_pos] ); + + /* if there is a new line in the string, will the line fit in the text + * space */ + while ( TRUE ) + { + continue_loop = FALSE; + for ( cnt = 0; cnt < cur_seg_len; ++cnt ) + { + if ( string[cur_seg_starting_pos + cnt] == '\n' ) + { + seg_len = XinFontTextWidthGet( font, + &string[cur_seg_starting_pos], + cnt ); + if ( seg_len <= internal_pix_width ) + { + add_seg( text, cur_seg_starting_pos ); + cur_seg_starting_pos += cnt + 1; + cur_seg_len = strlen( &string[cur_seg_starting_pos] ); + continue_loop = TRUE; + break; + } + else + { + continue_loop = FALSE; + break; + } + } + } + if ( !continue_loop ) + break; + } + + this_seg_len = min( avg_line_len, cur_seg_len ); + if ( this_seg_len == 0 ) + this_seg_len = 1; + + /* find character that is beyond internal_pix_width */ + while ( TRUE ) + { + seg_len = XinFontTextWidthGet( font, + &string[cur_seg_starting_pos], + this_seg_len ); + if ( seg_len > internal_pix_width ) + break; + if ( seg_len <= internal_pix_width && + string[cur_seg_starting_pos + this_seg_len] == '\0' ) + { + /* this is the last segment of the string */ + add_seg( text, cur_seg_starting_pos ); + return; + } + ++this_seg_len; + } + + /* add the first segment */ + add_seg( text, cur_seg_starting_pos ); + + /* find character that is just below internal_pix_width */ + while ( this_seg_len > 1 ) + { + --this_seg_len; + seg_len = XinFontTextWidthGet( font, + &string[cur_seg_starting_pos], + this_seg_len ); + if ( seg_len < internal_pix_width ) + break; + } + + /* find possible word break */ + possible_word_break = this_seg_len; + while ( possible_word_break > 0 ) + { + if ( !is_word_char( string[cur_seg_starting_pos + possible_word_break] ) ) + break; + --possible_word_break; + } + + /* if there is no possible word break, then break at this_seg_len */ + if ( possible_word_break == 0 ) + word_break = this_seg_len; + else + word_break = possible_word_break; + + /* move forward so that word break is on a word */ + while ( !is_word_char( string[cur_seg_starting_pos + word_break] ) ) + ++word_break; + + ++cur_seg; + cur_seg_starting_pos += word_break; + } + + /* If the text is empty, there will be no segments and nbr_lines will still + be zero. This is not a good state for the text object. RGM */ + if ( text->nbr_lines == 0 ) + add_seg( text, 0 ); +} + +/* Returns len, or len truncated to the available space in the buffer */ +static int +reallocate_text( XI_TEXT * text, int len, BOOLEAN setting_buffer_size ) +{ + int llen, new_len; + + llen = len; + if ( ! setting_buffer_size ) + { + llen = text->buffer_size; + if ( (!text->var_len_text) && len > text->buffer_size ) + len = text->buffer_size; + } + if ( llen < text->min_buffer_size ) + llen = text->min_buffer_size; + if ( text->var_len_text ) + new_len = NEW_LEN( llen ); + else + new_len = llen; + if ( new_len != text->allocated_length ) + { + if ( text->string ) + text->string = ( char * ) xi_tree_realloc( text->string, new_len ); + else + text->string = ( char * ) xi_tree_malloc( new_len, text ); + } + text->allocated_length = new_len; + text->buffer_size = llen; + return len; +} + +/* +this function sets the text of an xi_text. +*/ +void +xi_text_set( XI_TEXT * text, const char *string ) +{ + int len; + XinFont *font; + BOOLEAN restart = FALSE; + + if ( text->string ) + if ( strcmp( text->string, string ) == 0 && + text->initialized ) + return; + text->initialized = TRUE; + if ( xi_text_editing_is( text ) ) + { + xi_text_editing_stop( text ); + restart = TRUE; + } + font = text->font; + XinWindowFontMap( text->win, font ); + len = reallocate_text( text, strlen( string ) + 1, FALSE ); + if ( text->scrollbar ) + { + if ( !text->sb_width ) + text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth ); + text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA; + } + else + text->internal_pix_width = text->pix_width; + memcpy( text->string, string, len ); + text->string[len - 1] = '\0'; + if ( text->multi_line ) + xi_text_wrap_internal( text ); + if ( text->sb_win ) + { + if ( text->multi_line ) + calc_delta_y( text ); + else + calc_delta_x( text ); + xi_text_sb_set( text ); + } + if ( restart ) + { + xi_text_editing_start( text ); + if ( xi_get_attrib( text->parent_obj ) & XI_ATR_AUTOSELECT ) + xi_text_selection_set_internal( text, 0, SHRT_MAX, + 0, TRUE, TRUE ); + } +} + +/* +This function should be called after a cell request that reallocated the buffer. +*/ +void xi_text_reinitialize( XI_TEXT* text ) +{ + int len; + BOOLEAN restart = FALSE; + + text->initialized = TRUE; + if ( xi_text_editing_is( text ) ) + { + xi_text_editing_stop( text ); + restart = TRUE; + } + len = strlen( text->string ); + text->allocated_length = len; + if ( text->scrollbar ) + { + if ( !text->sb_width ) + text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth ); + text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA; + } + else + text->internal_pix_width = text->pix_width; + if ( text->multi_line ) + xi_text_wrap_internal( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + if ( restart ) + { + xi_text_editing_start( text ); + if ( xi_get_attrib( text->parent_obj ) & XI_ATR_AUTOSELECT ) + xi_text_selection_set_internal( text, 0, SHRT_MAX, + 0, TRUE, TRUE ); + } +} + +/* +this function wraps the text of an xi_text. +*/ +void +xi_text_wrap( XI_TEXT * text ) +{ + XinFont *font; + BOOLEAN restart = FALSE; + + if ( xi_text_editing_is( text ) ) + { + xi_text_editing_stop( text ); + restart = TRUE; + } + font = text->font; + XinWindowFontMap( text->win, font ); + if ( text->scrollbar ) + { + if ( !text->sb_width ) + text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth ); + text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA; + } + else + text->internal_pix_width = text->pix_width; + if ( text->multi_line ) + xi_text_wrap_internal( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + if ( restart ) + xi_text_editing_start( text ); +} + +/* +this function sets the text of an xi_text. if the pix_width has changed from +the last time this function was called, then wrapping is performed even if the +text is the same. set_font is used by the list. when setting lots of text, +the list knows that the font for the xi_text currently being set is the same +font as the xi_text last set. this eliminates a call to the windowing system +to set the font. +*/ +void +xi_text_pix_width_and_text_set( XI_TEXT * text, char *string, int pix_width, BOOLEAN set_font ) +{ + int len; + XinFont *font; + BOOLEAN restart = FALSE; + + if ( text->string ) + if ( text->pix_width == pix_width && + strcmp( text->string, string ) == 0 && + text->initialized ) + return; + text->initialized = TRUE; + if ( xi_text_editing_is( text ) ) + { + xi_text_editing_stop( text ); + restart = TRUE; + } + font = text->font; + if ( set_font ) + XinWindowFontMap( text->win, font ); + len = reallocate_text( text, strlen( string ) + 1, FALSE ); + text->pix_width = pix_width; + if ( text->scrollbar ) + { + if ( !text->sb_width ) + text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth ); + text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA; + } + else + text->internal_pix_width = text->pix_width; + memcpy( text->string, string, len ); + text->string[ len - 1 ] = '\0'; + if ( text->multi_line ) + xi_text_wrap_internal( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + if ( restart ) + { + xi_text_editing_start( text ); + if ( xi_get_attrib( text->parent_obj ) & XI_ATR_AUTOSELECT ) + xi_text_selection_set_internal( text, 0, SHRT_MAX, + 0, TRUE, TRUE ); + } +} + +/* +this function sets the pix width of an xi_text. +*/ +void +xi_text_pix_width_set( XI_TEXT * text, int pix_width ) +{ + XinFont *font; + BOOLEAN restart = FALSE; + + if ( text->string ) + if ( text->pix_width == pix_width && + text->initialized ) + return; + text->initialized = TRUE; + if ( xi_text_editing_is( text ) ) + { + xi_text_editing_stop( text ); + restart = TRUE; + } + font = text->font; + XinWindowFontMap( text->win, font ); + text->pix_width = pix_width; + if ( text->scrollbar ) + { + if ( !text->sb_width ) + text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth ); + text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA; + } + else + text->internal_pix_width = text->pix_width; + if ( text->multi_line ) + xi_text_wrap_internal( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + if ( restart ) + xi_text_editing_start( text ); +} + +void +xi_text_destruct( XI_TEXT * text ) +{ + if ( text->sb_win ) + if ( !xi_itf_in_event_destroy( text->itf ) ) + XinWindowDestroy( text->sb_win ); + xi_tree_free( text ); +} + +/* +draws the rectangle to the right of text on any line. after drawing the +text (in opaque mode), there often is still a small amount of space to the +right of the text, and to the left of the right edge of the edit control. +this function fills that space with the background color. + +for a right justified field, this function draws the rectangle to the left +of the text and to the right of the left edge of the edit control. +*/ +static void +draw_end_rect( XI_TEXT * text, char *str, int len, int left, int right, + int baseline, XinDrawTools * save_dt, int delta_x ) +{ + int x; + XinRect r; + XinDrawTools dt; + + x = XinFontTextWidthGet( text->font, str, len ); + r.top = baseline - text->leading - text->ascent; + r.bottom = baseline + text->descent; + if ( text->right_justify ) + { + r.left = left; + r.right = right - x + delta_x; + } + else + { + r.left = left + x - delta_x; + r.right = right; + } + if ( r.left < r.right ) + { + dt = *save_dt; + dt.brush.fore_color = text->back_color_in_use; + dt.brush.pattern = XinBrushSolid; + dt.pen.pattern = XinPenHollow; + dt.pen.width = 1; + dt.pen.fore_color = XI_COLOR_WHITE; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( text->win, &dt ); + xi_draw_rect( text->win, &r ); + XinWindowDrawToolsSet( text->win, save_dt ); + } +} + +static void +free_save_text_state( void ) +{ + xi_tree_free( save_text ); + save_text = NULL; +} + +static char * +alloc_password_string( int len, void *parent ) +{ + int cnt; + char *str; + + str = xi_tree_malloc( len + 1, parent ); + for ( cnt = 0; cnt < len; ++cnt ) + str[cnt] = '#'; + str[len] = '\0'; + return str; +} + +/* +this function draws the XI_TEXT. if save_text is set, then this function only +displays differences between save_text and text. +*/ +static void +xi_text_draw_internal( XI_TEXT * text, XinColor color, XinColor back_color, BOOLEAN do_carets ) +{ + XinRect rct; + char *s; + char *sws = NULL; + int cnt, + nbr_lines = 0, + baseline, + line_to_draw, + top_of_rect; + XinWindow win = text->win; + XI_TEXT_LINE_BREAK *lb; + XinDrawTools save_dt; + BOOLEAN turn_caret_on = FALSE; + + if ( do_carets && xi_text_editing_is( text ) ) + { + xi_text_caret_off( text ); + turn_caret_on = TRUE; + } + if ( color ) + { + text->fore_color_in_use = color; + text->back_color_in_use = back_color; + } + else + { + text->fore_color_in_use = text->fore_color; + text->back_color_in_use = text->back_color; + } + XinWindowFontMap( text->win, text->font ); + rct = text->prect; + rct.right = rct.left + text->internal_pix_width; + xi_rect_intersect( &rct, &rct, &text->clip_rect ); + xi_set_clip( win, &rct ); + XinWindowDrawToolsGet( win, &save_dt ); + if ( text->multi_line ) + { + if ( text->max_lines_to_draw ) + nbr_lines = min( xi_text_nbr_lines_get( text ), text->max_lines_to_draw ); + else + nbr_lines = xi_text_nbr_lines_get( text ); + if ( text->delta_y + nbr_lines > text->nbr_lines ) + nbr_lines -= ( text->delta_y + nbr_lines - text->nbr_lines ); + } + s = text->string; + if ( save_text ) + sws = save_text->string; + if ( text->multi_line ) + { + for ( cnt = 0, line_to_draw = text->delta_y; + cnt < nbr_lines; ++cnt, ++line_to_draw ) + { + int len = -1; + XinDrawTools dt; + char *str; + BOOLEAN dont_draw = FALSE; + + lb = &text->line_breaks[line_to_draw]; + if ( line_to_draw < text->nbr_lines - 1 ) + len = xi_text_line_break_get( text, line_to_draw + 1 ) - + xi_text_line_break_get( text, line_to_draw ); +//#if XIWS == XIWS_WM +// baseline = rct.top + 8; +//#else + baseline = rct.top + text->leading + text->ascent; +// #endif + str = &s[xi_text_line_break_get( text, line_to_draw )]; + if ( len == -1 ) + len = strlen( str ); + if ( ( &s[xi_text_line_break_get( text, line_to_draw )] )[len - 1] == '\n' ) + len--; + if ( save_text && line_to_draw < save_text->nbr_lines ) + { + int sw_len = -1; + char *sw_str; + + if ( line_to_draw < save_text->nbr_lines - 1 ) + sw_len = xi_text_line_break_get( save_text, line_to_draw + 1 ) - xi_text_line_break_get( save_text, line_to_draw ); + sw_str = &sws[xi_text_line_break_get( save_text, line_to_draw )]; + if ( sw_len == -1 ) + sw_len = strlen( sw_str ); + if ( ( &sws[xi_text_line_break_get( save_text, line_to_draw )] )[sw_len - 1] == '\n' ) + sw_len--; + if ( ( sw_len == len ) && + ( strncmp( str, sw_str, len ) == 0 ) && + ( text->line_breaks[line_to_draw].ip1 == save_text->line_breaks[line_to_draw].ip1 ) && + ( text->line_breaks[line_to_draw].ip2 == save_text->line_breaks[line_to_draw].ip2 ) ) + dont_draw = TRUE; + /* This piece of code causes problems with scrolling. Why is it here? + * if ( save_text->line_breaks[line_to_draw].ip1 != -1 && + * save_text->line_breaks[line_to_draw].ip1 == + * save_text->line_breaks[line_to_draw].ip2 ) dont_draw = FALSE; */ + } + if ( !dont_draw ) + { + dt = save_dt; + dt.text_fore_color = text->fore_color_in_use; + dt.text_back_color = text->back_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( text->win, &dt ); + if ( lb->ip1 != lb->ip2 ) + { + if ( lb->ip1 ) + xi_draw_text( win, text->font, rct.left, baseline, + str, lb->ip1 ); + dt = save_dt; + dt.text_fore_color = text->back_color_in_use; + dt.text_back_color = text->fore_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( win, &dt ); + if ( lb->ip2 < len ) + { + int x; + + x = XinFontTextWidthGet( text->font, str, lb->ip1 ); + xi_draw_text( win, text->font, rct.left + x, baseline, + &str[lb->ip1], lb->ip2 - lb->ip1 ); + dt = save_dt; + dt.text_fore_color = text->fore_color_in_use; + dt.text_back_color = text->back_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( text->win, &dt ); + x = XinFontTextWidthGet( text->font, str, lb->ip2 ); + xi_draw_text( win, text->font, rct.left + x, baseline, + &str[lb->ip2], len - lb->ip2 ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, 0 ); + XinWindowDrawToolsSet( win, &save_dt ); + } + else + { + int x; + + dt = save_dt; + dt.text_fore_color = text->back_color_in_use; + dt.text_back_color = text->fore_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( win, &dt ); + x = XinFontTextWidthGet( text->font, str, lb->ip1 ); + xi_draw_text( win, text->font, rct.left + x, baseline, + &str[lb->ip1], len - lb->ip1 ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, 0 ); + XinWindowDrawToolsSet( text->win, &save_dt ); + } + } + else + { + xi_draw_text( win, text->font, rct.left, baseline, + &s[xi_text_line_break_get( text, line_to_draw )], len ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, 0 ); + } + } +#if XIWS == XIWS_WM + rct.top += text->font_height; +#else + rct.top += xi_text_font_height_get( text ); +#endif + } + } + if ( !text->multi_line ) + { + char *str; + char *sw_str = NULL; + int len, + sw_len; + BOOLEAN dont_draw; + + len = strlen( text->string ); + if ( text->password ) + str = alloc_password_string( len, text ); + else + str = text->string; +//#if XIWS == XI_WMWS +// baseline = rct.top + 8; +//#else + baseline = rct.top + text->leading + text->ascent; +//#endif + dont_draw = FALSE; + if ( save_text ) + { + sw_len = strlen( save_text->string ); + if ( save_text->password ) + sw_str = alloc_password_string( sw_len, save_text ); + else + sw_str = save_text->string; + if ( ( sw_len == len ) && + ( strncmp( str, sw_str, len ) == 0 ) && + ( ( ( text->ip1 == save_text->ip1 ) && ( text->ip2 == save_text->ip2 ) ) || + ( ( text->ip1 == text->ip2 ) && ( save_text->ip1 == save_text->ip2 ) ) ) + ) + dont_draw = TRUE; + } + if ( !dont_draw ) + { + int delta_x_pix; + XinDrawTools dt; + int text_pix_len = XinFontTextWidthGet( text->font, str, -1 ); + + dt = save_dt; + dt.text_fore_color = text->fore_color_in_use; + dt.text_back_color = text->back_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( text->win, &dt ); + if ( text->right_justify ) + { + delta_x_pix = XinFontTextWidthGet( text->font, + &str[len - text->delta_x], text->delta_x ); + if ( text->ip1 != text->ip2 ) + { + if ( text->ip1 ) + xi_draw_text( win, text->font, + rct.right - text_pix_len + delta_x_pix, baseline, str, + text->ip1 ); + dt = save_dt; + dt.text_fore_color = text->back_color_in_use; + dt.text_back_color = text->fore_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( win, &dt ); + if ( text->ip2 < len ) + { + int x; + + x = XinFontTextWidthGet( text->font, &str[text->ip1], strlen( &str[text->ip1] ) ); + xi_draw_text( win, text->font, rct.right - x + delta_x_pix, baseline, + &str[text->ip1], text->ip2 - text->ip1 ); + dt = save_dt; + dt.text_fore_color = text->fore_color_in_use; + dt.text_back_color = text->back_color_in_use; + XinWindowDrawToolsSet( win, &dt ); + x = XinFontTextWidthGet( text->font, &str[text->ip2], strlen( &str[text->ip2] ) ); + xi_draw_text( win, text->font, rct.right - x + delta_x_pix, baseline, + &str[text->ip2], len - text->ip2 ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, delta_x_pix ); + XinWindowDrawToolsSet( win, &save_dt ); + } + else + { + int x; + int len_in_pix = XinFontTextWidthGet( text->font, str, -1 ); + + dt = save_dt; + dt.text_fore_color = text->back_color_in_use; + dt.text_back_color = text->fore_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( win, &dt ); + x = XinFontTextWidthGet( text->font, str, text->ip1 ); + xi_draw_text( win, text->font, rct.right - len_in_pix + x + delta_x_pix, baseline, + &str[text->ip1], len - text->ip1 ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, delta_x_pix ); + XinWindowDrawToolsSet( text->win, &save_dt ); + } + } + else + { + int x; + + x = XinFontTextWidthGet( text->font, str, -1 ); + xi_draw_text( win, text->font, rct.right - x + delta_x_pix, baseline, + str, len ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, delta_x_pix ); + } + } + else + { + delta_x_pix = XinFontTextWidthGet( text->font, str, text->delta_x ); + if ( text->ip1 != text->ip2 ) + { + if ( text->ip1 ) + xi_draw_text( win, text->font, rct.left - delta_x_pix, baseline, + str, text->ip1 ); + dt = save_dt; + dt.text_fore_color = text->back_color_in_use; + dt.text_back_color = text->fore_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( win, &dt ); + if ( text->ip2 < len ) + { + int x; + + x = XinFontTextWidthGet( text->font, str, text->ip1 ); + xi_draw_text( win, text->font, rct.left + x - delta_x_pix, baseline, + &str[text->ip1], text->ip2 - text->ip1 ); + dt = save_dt; + dt.text_fore_color = text->fore_color_in_use; + dt.text_back_color = text->back_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( win, &dt ); + x = XinFontTextWidthGet( text->font, str, text->ip2 ); + xi_draw_text( win, text->font, rct.left + x - delta_x_pix, baseline, + &str[text->ip2], len - text->ip2 ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, delta_x_pix ); + XinWindowDrawToolsSet( win, &save_dt ); + } + else + { + int x; + + dt = save_dt; + dt.text_fore_color = text->back_color_in_use; + dt.text_back_color = text->fore_color_in_use; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( win, &dt ); + x = XinFontTextWidthGet( text->font, str, text->ip1 ); + xi_draw_text( win, text->font, rct.left + x - delta_x_pix, baseline, + &str[text->ip1], len - text->ip1 ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, delta_x_pix ); + XinWindowDrawToolsSet( text->win, &save_dt ); + } + } + else + { + xi_draw_text( win, text->font, rct.left - delta_x_pix, baseline, + str, len ); + draw_end_rect( text, str, len, rct.left, rct.right, + baseline, &save_dt, delta_x_pix ); + } + } + } + if ( text->password ) + { + xi_tree_free( str ); + if ( save_text ) + xi_tree_free( sw_str ); + } + } + if ( text->multi_line ) + { + top_of_rect = text->prect.top + nbr_lines * text->font_height; + if ( top_of_rect < text->prect.bottom ) + { + XinRect r; + XinDrawTools dt; + + r.top = top_of_rect; + r.left = text->prect.left; + r.bottom = text->prect.bottom; + r.right = text->prect.left + text->internal_pix_width; + dt = save_dt; + dt.brush.fore_color = text->back_color_in_use; + dt.brush.pattern = XinBrushSolid; + dt.pen.pattern = XinPenHollow; + dt.pen.width = 1; + dt.pen.fore_color = XI_COLOR_WHITE; + dt.opaque_text = TRUE; + XinWindowDrawToolsSet( text->win, &dt ); + xi_draw_rect( text->win, &r ); + } + } +#if 0 + /* draw line to right of text if there is a scrollbar */ + if ( text->scrollbar ) + { + XinPoint p; + XinDrawTools dt; + + dt = save_dt; + dt.pen.pattern = XinPenSolid; + dt.pen.width = 1; + dt.pen.fore_color = text->fore_color_in_use; + XinWindowDrawToolsSet( text->win, &dt ); + p.h = text->prect.left + text->internal_pix_width; + p.v = text->prect.top; + xi_move_to( text->win, p ); + p.v = text->prect.bottom; + xi_draw_line( text->win, p ); + } +#endif + /* If there is a scrollbar, fill the space between the text and the sb, and + * the sb's space if we aren't editing. */ + if ( text->scrollbar ) + { + XinRect rect; + XinDrawTools dt; + + dt = save_dt; + dt.pen.pattern = XinPenSolid; + dt.pen.width = 1; + dt.pen.fore_color = text->back_color_in_use; + dt.brush.fore_color = text->back_color_in_use; + dt.brush.pattern = XinBrushSolid; + XinWindowDrawToolsSet( text->win, &dt ); + rect = text->prect; + rect.left = text->prect.left + text->internal_pix_width; + if ( text->sb_win ) + rect.right = rect.right - text->sb_width; + xi_rect_intersect( &rect, &rect, &text->clip_rect ); + xi_set_clip( win, &rect ); + xi_draw_rect( text->win, &rect ); + } + XinWindowDrawToolsSet( text->win, &save_dt ); + if ( turn_caret_on ) + xi_text_caret_on( text ); +} + +void +xi_text_draw( XI_TEXT * text, XinColor color, XinColor back_color, BOOLEAN update ) +{ + xi_text_draw_internal( text, color, back_color, ( BOOLEAN ) ! update ); +} + +/* +there are two sets of state for insertion points. the state that this module +initially modifies when editing is the ip1 and ip2 in the xi_text structure. +from this, for convenience when drawing the edit control, and for convenience +when turning on the caret as appropriate, we calculate insertion points for +every line in the line_breaks array. this function is used by recalc_line_ips, +which does calculation of insertion points for every line in the line_breaks +array. + +this function is only used if the xi_text is multi_line. +*/ +static void +recalc_single_ip( XI_TEXT * text, int ip, BOOLEAN starting, int active_ip ) +{ + int line_cnt; + int total_cnt, + old_total_cnt; + + total_cnt = 0; + for ( line_cnt = 0; line_cnt < text->nbr_lines; ++line_cnt ) + { + int line_len; + + if ( line_cnt < text->nbr_lines - 1 ) + line_len = text->line_breaks[line_cnt + 1].line_break - + text->line_breaks[line_cnt].line_break; + else + line_len = strlen( &text->string[text->line_breaks[line_cnt].line_break] ); + old_total_cnt = total_cnt; + total_cnt += line_len; + if ( ip < total_cnt || ( line_cnt == text->nbr_lines - 1 && ip <= total_cnt ) ) + { + int this_line_cnt; + + this_line_cnt = ip - old_total_cnt; + if ( starting ) + text->line_breaks[line_cnt].ip1 = this_line_cnt; + else + text->line_breaks[line_cnt].ip2 = this_line_cnt; + if ( ip == active_ip ) + text->line_breaks[line_cnt].active_ip = this_line_cnt; + return; + } + } +} + +/* +there are two sets of state for insertion points. the state that this module +initially modifies when editing is the ip1 and ip2 in the XI_TEXT structure. +from this, for convenience when drawing the edit control, and for convenience +when turning on the caret as appropriate, we calculate insertion points for +every line in the line_breaks array. this function does the calculation of +insertion points for the line_breaks array. + +for each line in the line_breaks array: +- if ip1 and ip2 both == -1, then the caret is not on this line, and no text + on this line is selected. +- if ip1 and ip2 are both != -1, and they are not equal, then the text on this + line from ip1 to ip2 is selected. +- if ip1 and ip2 are both != -1, and they are equal, then the caret is placed + at the indicated position in ip1. +- it is invalid for either ip1 or ip2 to be -1 where the other is not. + +this function is used only if the xi_text is multi_line. +*/ +static void +recalc_line_ips( XI_TEXT * text ) +{ + int cnt; + XI_TEXT_LINE_BREAK *lb; + enum + { + state_before_sel, + state_in_sel, + state_after_sel + } state; + int active_ip; + + active_ip = ( text->selection_start_ip == text->ip1 ) ? text->ip2 : text->ip1; + for ( cnt = 0, lb = text->line_breaks; cnt < text->nbr_lines; ++cnt, ++lb ) + { + lb->ip1 = lb->ip2 = -1; + lb->active_ip = -2; + } + recalc_single_ip( text, text->ip1, TRUE, active_ip ); + recalc_single_ip( text, text->ip2, FALSE, active_ip ); + state = state_before_sel; + for ( cnt = 0, lb = text->line_breaks; cnt < text->nbr_lines; ++cnt, ++lb ) + { + if ( lb->ip1 == -1 && lb->ip2 != -1 ) + { + lb->ip1 = 0; + state = state_after_sel; + } + if ( lb->ip1 != -1 && lb->ip2 == -1 ) + { + /* there is no way that lb->ip1 can not be -1, and lb->ip2 is -1 for the + * last line, hence the following line will always work. */ + lb->ip2 = text->line_breaks[cnt + 1].line_break - lb->line_break; + state = state_in_sel; + } + if ( lb->ip1 == -1 && lb->ip2 == -1 && state == state_in_sel ) + { + lb->ip1 = 0; + if ( cnt < text->nbr_lines - 1 ) + lb->ip2 = text->line_breaks[cnt + 1].line_break - lb->line_break; + else + lb->ip2 = strlen( &text->string[text->line_breaks[cnt].line_break] ); + } + } +} + +/* +this function sets the selection. if do_carets is false, then the caret is +not turned on after setting selection. this happens when editing is stopped. +*/ +void +xi_text_selection_set_internal( XI_TEXT * text, int ip1, int ip2, + int selection_start_ip, BOOLEAN do_carets, BOOLEAN map_font ) +{ + int len; + + if ( ! text->string ) + return; + if ( ip1 > ip2 ) + { + int temp; + + temp = ip1; + ip1 = ip2; + ip2 = temp; + } + text->ip1 = ip1; + len = strlen( text->string ); + if ( ip2 > len ) + ip2 = len; + text->ip2 = ip2; + text->selection_start_ip = selection_start_ip; + if ( !text->editing && do_carets ) + return; + if ( map_font ) + XinWindowFontMap( text->win, text->font ); + if ( do_carets ) + xi_text_caret_off( text ); + if ( text->multi_line ) + { + xi_text_wrap_internal( text ); + recalc_line_ips( text ); + calc_delta_y( text ); + } + else + calc_delta_x( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + xi_text_draw_internal( text, 0L, 0L, FALSE ); + if ( do_carets ) + xi_text_caret_on( text ); +} + +void +xi_text_selection_set( XI_TEXT * text, int ip1, int ip2 ) +{ + xi_text_selection_set_internal( text, ip1, ip2, ip2, TRUE, TRUE ); +} + +static void +xi_text_caret_off( XI_TEXT * text ) +{ + XinWindowCaretOff( text->win ); +} + +static void +xi_text_caret_on( XI_TEXT * text ) +{ + int cnt, + caret_base; + XI_TEXT_LINE_BREAK *lb; + int nbr_lines, + caret_line; + + if ( text->multi_line ) + { + if ( text->max_lines_to_draw ) + nbr_lines = min( xi_text_nbr_lines_get( text ), text->max_lines_to_draw ); + else + nbr_lines = xi_text_nbr_lines_get( text ); + if ( text->delta_y + nbr_lines > text->nbr_lines ) + nbr_lines -= ( text->delta_y + nbr_lines - text->nbr_lines ); + caret_base = text->prect.top + text->font_height; + for ( cnt = 0, caret_line = text->delta_y; + cnt < nbr_lines; + ++cnt, ++caret_line ) + { + int ip = 0; + BOOLEAN set_caret = FALSE; + + lb = &text->line_breaks[caret_line]; + if ( lb->ip1 == lb->active_ip ) + { + ip = lb->ip1; + set_caret = TRUE; + } + if ( lb->ip2 == lb->active_ip ) + { + ip = lb->ip2; + set_caret = TRUE; + } + if ( set_caret ) + { + char *str; + int x; + XinRect rect; + + str = &text->string[lb->line_break]; + x = XinFontTextWidthGet( text->font, str, ip ); + rect = text->prect; + rect.right = rect.left + text->internal_pix_width; + xi_rect_intersect( &rect, &rect, &text->clip_rect ); + xi_caret_on( text->win, text->prect.left + x, caret_base, + text->font_height, &rect ); + return; + } + caret_base += text->font_height; + } + } + else + { + int caret_base = text->prect.top + text->font_height; + int ip = ( text->selection_start_ip == text->ip1 ) ? text->ip2 : text->ip1; + int x; + char *pwc = "#"; + int pwc_len = 0; + + if ( text->password ) + { + pwc_len = XinFontTextWidthGet( text->font, pwc, 1 ); + x = pwc_len * ip; + } + else + x = XinFontTextWidthGet( text->font, text->string, ip ); + + if ( text->right_justify ) + { + int len_in_pix = XinFontTextWidthGet( text->font, text->string, -1 ); + int len = strlen( text->string ); + int delta_x_pix = XinFontTextWidthGet( text->font, + &text->string[len - text->delta_x], text->delta_x ); + int hpos = text->prect.right - len_in_pix + delta_x_pix + x; + XinRect r1 = text->prect; + XinRect r2 = text->clip_rect; + XinRect r3; + + /* only turn on caret if caret is in intersection of prect and clipping + * rect */ + if ( xi_rect_intersect( &r3, &r1, &r2 ) ) + { + int caret_height = text->font_height; + + if ( hpos >= r3.left && hpos <= r3.right ) + { + if ( caret_base > r3.bottom ) + { + int delta = caret_base - r3.bottom; + + caret_base -= delta; + caret_height -= delta; + } + xi_caret_on( text->win, hpos, + caret_base, caret_height, &r3 ); + } + } + } + else + { + int delta_x_pix; + XinRect r1 = text->prect; + XinRect r2 = text->clip_rect; + XinRect r3; + int hpos; + + if ( text->password ) + delta_x_pix = pwc_len * text->delta_x; + else + delta_x_pix = XinFontTextWidthGet( text->font, text->string, text->delta_x ); + hpos = text->prect.left + x - delta_x_pix; + /* only turn on caret if caret is in intersection of prect and clipping + * rect */ + if ( xi_rect_intersect( &r3, &r1, &r2 ) ) + { + int caret_height = text->font_height; + + if ( hpos >= r3.left && hpos <= r3.right ) + { + xi_caret_on( text->win, hpos, caret_base, + caret_height, &r3 ); + } + } + } + } +} + +void +xi_text_editing_start( XI_TEXT * text ) +{ + if ( text->editing == TRUE ) + return; + text->editing = TRUE; + if ( text->scrollbar && !text->scrollbar_always_visible ) + { + XinWindowDef Def; + XinRect rct; + + MEMCLEAR( Def ); + Def.control_id = text->cid; + Def.type = XinWindowTypeVerticalScrollBar; + rct.top = text->prect.top; + rct.bottom = text->prect.bottom; + rct.right = text->prect.left + text->internal_pix_width + SB_DELTA + text->sb_width; + rct.left = text->prect.left + text->internal_pix_width + SB_DELTA; + Def.p_rect = &rct; + Def.title = ""; + Def.visible = TRUE; + Def.enabled = TRUE; + Def.parent = text->win; + if ( text->sb_win != XI_NULL_WINDOW ) + XinWindowDestroy( text->sb_win ); + text->sb_win = XinWindowCreate( &Def ); + } + if ( text->multi_line ) + { + xi_text_wrap_internal( text ); + recalc_line_ips( text ); + calc_delta_y( text ); + } + else + calc_delta_x( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + xi_text_draw_internal( text, 0L, 0L, FALSE ); + xi_text_caret_on( text ); +} + +void +xi_text_selection_get( XI_TEXT * text, int *c1, int *c2 ) +{ + *c1 = text->ip1; + *c2 = text->ip2; +} + +void +xi_text_selection_get_internal( XI_TEXT * text, int *c1, int *c2, int *start_ip ) +{ + *c1 = text->ip1; + *c2 = text->ip2; + *start_ip = text->selection_start_ip; +} + +static void +save_text_state( XI_TEXT * text ) +{ + save_text = xi_tree_malloc( sizeof( XI_TEXT ), NULL ); + save_text->string = xi_tree_malloc( strlen( text->string ) + 1, save_text ); + save_text->font = text->font; + strcpy( save_text->string, text->string ); + if ( text->multi_line ) + { + save_text->line_breaks = xi_tree_malloc( sizeof( XI_TEXT_LINE_BREAK ) * text->nbr_lines, text ); + memcpy( save_text->line_breaks, text->line_breaks, sizeof( XI_TEXT_LINE_BREAK ) * text->nbr_lines ); + } + save_text->nbr_lines = text->nbr_lines; + save_text->ip1 = text->ip1; + save_text->ip2 = text->ip2; + save_text->delta_y = text->delta_y; + save_text->delta_x = text->delta_x; + save_text->selection_start_ip = text->selection_start_ip; +} + +static void +display_if_necessary( XI_TEXT * text, BOOLEAN recalc_delta_y ) +{ +/* This contains a hack for Mac - xvt_dwin_scroll_rect is not called + the scrollbar position does not update */ +#if XIWS == XIWS_MAC + BOOLEAN scrolled_rect = FALSE; +#endif + xi_text_caret_off( text ); + if ( text->multi_line ) + { + xi_text_wrap_internal( text ); + recalc_line_ips( text ); + } + xi_text_draw( text, 0L, 0L, FALSE ); + if ( text->multi_line ) + { + if ( recalc_delta_y ) + calc_delta_y( text ); + } + else + calc_delta_x( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + if ( save_text && save_text->delta_y != text->delta_y ) + { + int delta = save_text->delta_y - text->delta_y; + XinRect r; + + /* need to do this here, because a Paint event will come thru */ + free_save_text_state( ); + xi_set_update_obj( text->parent_obj ); + r = text->prect; + r.bottom = r.top + text->max_lines_to_draw * text->font_height; + r.right = r.left + text->internal_pix_width; + xi_scroll_rect( text->win, &r, 0, + delta * text->font_height ); +#if XIWS == XIWS_MAC + scrolled_rect = TRUE; +#endif + + } + if ( save_text && save_text->delta_x != text->delta_x ) + { + if ( text->right_justify ) + { + int old_delta_x_pix = XinFontTextWidthGet( save_text->font, + &save_text->string[strlen( save_text->string ) - save_text->delta_x], + save_text->delta_x ); + int delta_x_pix = XinFontTextWidthGet( text->font, + &text->string[strlen( text->string ) - text->delta_x], + text->delta_x ); + XinRect r; + + /* need to do this here, because a Paint event will come thru */ + free_save_text_state( ); + xi_set_update_obj( text->parent_obj ); + r = text->prect; + r.bottom = r.top + text->font_height; + r.left = r.right - text->internal_pix_width; + xi_scroll_rect( text->win, &r, delta_x_pix - old_delta_x_pix, 0 ); +#if XIWS == XIWS_MAC + scrolled_rect = TRUE; +#endif + } + else + { + int old_delta_x_pix = XinFontTextWidthGet( save_text->font, save_text->string, + save_text->delta_x ); + int delta_x_pix = XinFontTextWidthGet( text->font, text->string, + text->delta_x ); + XinRect r; + + /* need to do this here, because a Paint event will come thru */ + free_save_text_state( ); + xi_set_update_obj( text->parent_obj ); + r = text->prect; + r.bottom = r.top + text->font_height; + r.right = r.left + text->internal_pix_width; + xi_scroll_rect( text->win, &r, old_delta_x_pix - delta_x_pix, 0 ); +#if XIWS == XIWS_MAC + scrolled_rect = TRUE; +#endif + } + } +#if XIWS == XIWS_MAC + if (!scrolled_rect) + { + XinRect r; + r = text->prect; + r.bottom = r.top + text->font_height; + r.right = r.left + text->internal_pix_width; + xi_scroll_rect( text->win, &r, 0, 0 ); + } +#endif + xi_text_caret_on( text ); + if ( save_text ) + free_save_text_state( ); +} + +static int +get_line_from_ip( XI_TEXT * text, int ip ) +{ + int cnt; + + for ( cnt = 0; cnt < text->nbr_lines; ++cnt ) + { + if ( text->line_breaks[cnt].line_break > ip ) + return ( cnt - 1 ); + } + return ( text->nbr_lines - 1 ); +} + +static void +calc_delta_y( XI_TEXT * text ) +{ + int ip, + line; + + if ( text->nbr_lines <= text->max_lines_to_draw ) + { + text->delta_y = 0; + return; + } + if ( text->ip1 == text->selection_start_ip ) + ip = text->ip2; + else + ip = text->ip1; + line = get_line_from_ip( text, ip ); + if ( line < text->delta_y ) + { + text->delta_y = line; + if ( text->nbr_lines - text->delta_y < text->max_lines_to_draw ) + text->delta_y = text->nbr_lines - text->max_lines_to_draw; + return; + } + if ( line > text->delta_y + ( text->max_lines_to_draw - 1 ) ) + { + text->delta_y += line - ( text->delta_y + ( text->max_lines_to_draw - 1 ) ); + if ( text->nbr_lines - text->delta_y < text->max_lines_to_draw ) + text->delta_y = text->nbr_lines - text->max_lines_to_draw; + return; + } + if ( text->nbr_lines - text->delta_y < text->max_lines_to_draw ) + text->delta_y = text->nbr_lines - text->max_lines_to_draw; +} + +/* +this function calculates text->delta_x such that the insertion point that is +not the selection start insertion point is visible. +*/ +static void +calc_delta_x( XI_TEXT * text ) +{ + int ip, + delta_x_pix, + dx, + ip_pix, + cnt; + int len = strlen( text->string ); + + if ( text->ip1 == text->selection_start_ip ) + ip = text->ip2; + else + ip = text->ip1; + if ( text->right_justify ) + { + /* for a right justified field, if the insertion point is to the right of + * the visible area, then delta_x is easy to calculate. it is the length + * of the string minus the insertion point. */ + if ( ( len - ip ) < text->delta_x ) + { + text->delta_x = len - ip; + return; + } + } + else + { + /* for a left justified field, if the insertion point is to the left of the + * visible area, then delta_x is easy to calculate. it is the insertion + * point. */ + if ( ip < text->delta_x ) + { + text->delta_x = ip; + return; + } + } + + if ( text->right_justify ) + { + /* for a right justified field, if the insertion point is to the left of + * the visible area, then the algorythm is as follows: 1. calculate the + * length of delta_x in pixels 2. calculate the length of the string from + * ip to the end of the string 3. calculate the number of pixels that we + * must make visible: (2) - (1) - internal pixel width 4. count the number + * of characters from delta_x, going to the left, until the length of the + * characters is greater than (3) */ + delta_x_pix = XinFontTextWidthGet( text->font, + &text->string[len - text->delta_x], text->delta_x ); + ip_pix = XinFontTextWidthGet( text->font, &text->string[ip], -1 ); + dx = ip_pix - delta_x_pix - text->internal_pix_width; + for ( cnt = text->delta_x; cnt < len; ++cnt ) + if ( XinFontTextWidthGet( text->font, &text->string[len - cnt], cnt - text->delta_x ) > dx ) + break; + text->delta_x = cnt; + } + else + { + /* for a left justified field, if the insertion point is to the right of + * the visible area, then the algorythm is as follows: 1. calculate the + * length of delta_x in pixels 2. calculate the length of the string from + * the beginning of the string to the insertion point 3. calculate the + * number of pixels that we must make visible: (2) - (1) - internal pixel + * width 4. count the number of characters from delta_x, going to the + * right, until the length of the characters is greater than (3) */ + delta_x_pix = XinFontTextWidthGet( text->font, text->string, text->delta_x ); + ip_pix = XinFontTextWidthGet( text->font, text->string, ip ); + dx = ip_pix - delta_x_pix - text->internal_pix_width; + for ( cnt = text->delta_x; cnt < len; ++cnt ) + if ( XinFontTextWidthGet( text->font, &text->string[text->delta_x], cnt - text->delta_x ) >= dx ) + break; + text->delta_x = cnt; + } +} + +/* +this is a utility function that returns the text and line length for a given line. + +this function is only used if the xi_text is multi_line. +*/ +static char * +get_line( XI_TEXT * text, int line, int *line_len ) +{ + int len; + char *s; + + s = &text->string[text->line_breaks[line].line_break]; + if ( line < text->nbr_lines - 1 ) + len = text->line_breaks[line + 1].line_break - + text->line_breaks[line].line_break; + else + len = strlen( s ); + if ( line_len ) + *line_len = len; + return s; +} + +/* +the functions key_left, key_right, key_line_home, key_line_end, key_word_left, + key_word_right, key_backspace, key_delete, key_character manipulate the xi_text + when editing. no modifications are necessary for single, multi_line, or + right justified edit controls. + +the functions key_up, key_page_up, key_down, key_page_down are only used for + multi-line edit controls. +*/ +static void +key_left( XI_TEXT * text, XinEvent * ep ) +{ + if ( text->ip1 == text->ip2 ) + { + if ( ep->v.character.shift ) + { + text->selection_start_ip = text->ip2; + if ( text->ip1 >= 1 ) + --text->ip1; + } + else + { + if ( text->ip1 >= 1 ) + text->selection_start_ip = text->ip1 = --text->ip2; + else + ep->v.character.ch = XI_KEY_BTAB; // AGA was here + } + } + else if ( text->ip1 == text->selection_start_ip ) + { + if ( ep->v.character.shift ) + text->ip2--; + else + text->selection_start_ip = text->ip1 = --text->ip2; + } + else + { + if ( ep->v.character.shift ) + { + if ( text->ip1 >= 1 ) + text->ip1--; + } + else + { + int new_ip = text->ip1; + + if ( text->ip1 >= 1 ) + new_ip = text->ip1 - 1; + else + ep->v.character.ch = XI_KEY_BTAB; // AGA was here + text->selection_start_ip = text->ip1 = text->ip2 = new_ip; + } + } + display_if_necessary( text, TRUE ); +} + +static void +key_right( XI_TEXT * text, XinEvent * ep ) +{ + if ( text->ip1 == text->ip2 ) + { + if ( ep->v.character.shift ) + { + text->selection_start_ip = text->ip1; + if ( text->ip2 < ( int ) strlen( text->string ) ) + ++text->ip2; + } + else + { + if ( text->ip2 < ( int ) strlen( text->string ) ) + text->selection_start_ip = text->ip1 = ++text->ip2; + else + ep->v.character.ch = '\t'; // AGA was here + } + } + else if ( text->ip2 == text->selection_start_ip ) + { + if ( ep->v.character.shift ) + text->ip1++; + else + text->selection_start_ip = text->ip2 = ++text->ip1; + } + else + { + if ( ep->v.character.shift ) + { + if ( text->ip2 < ( int ) strlen( text->string ) ) + text->ip2++; + } + else + { + int new_ip = text->ip2; + + if ( text->ip2 < ( int ) strlen( text->string ) ) + new_ip = text->ip2 + 1; + else + ep->v.character.ch = '\t'; // AGA was here + + text->selection_start_ip = text->ip1 = text->ip2 = new_ip; + } + } + display_if_necessary( text, TRUE ); +} + +static BOOLEAN +get_ip_one_line_above( XI_TEXT * text, int ip, int *new_ip ) +{ + int line, + pix_len; + char *s; + char *pls; + + line = get_line_from_ip( text, ip ); + if ( line >= 1 ) + { + int cnt, + len; + + s = get_line( text, line, NULL ); + pix_len = XinFontTextWidthGet( text->font, s, ip - text->line_breaks[line].line_break ); + pls = get_line( text, line - 1, &len ); + for ( cnt = 0; cnt < len; ++cnt ) + { + int lpix_len; + + lpix_len = XinFontTextWidthGet( text->font, pls, cnt ); + if ( lpix_len >= pix_len ) + { + *new_ip = text->line_breaks[line - 1].line_break + cnt; + return TRUE; + } + } + *new_ip = text->line_breaks[line - 1].line_break + cnt - 1; + return TRUE; + } + return FALSE; +} + +static BOOLEAN +key_up( XI_TEXT * text, XinEvent * ep, BOOLEAN redisplay ) +{ + if ( !text->multi_line ) + return FALSE; + if ( text->ip1 == text->ip2 ) + { + int new_ip; + + if ( get_ip_one_line_above( text, text->ip1, &new_ip ) ) + { + if ( ep->v.character.shift ) + { + text->ip1 = new_ip; + text->selection_start_ip = text->ip2; + } + else + text->selection_start_ip = text->ip1 = text->ip2 = new_ip; + if ( redisplay ) + display_if_necessary( text, TRUE ); + } + return TRUE; + } + if ( text->selection_start_ip == text->ip1 ) + { + int new_ip; + + if ( get_ip_one_line_above( text, text->ip2, &new_ip ) ) + { + if ( ep->v.character.shift ) + { + text->ip2 = new_ip; + if ( text->ip2 < text->ip1 ) + { + int temp; + + temp = text->ip1; + text->ip1 = text->ip2; + text->ip2 = temp; + text->selection_start_ip = text->ip2; + } + } + else + { + text->selection_start_ip = text->ip1 = text->ip2 = new_ip; + } + if ( redisplay ) + display_if_necessary( text, TRUE ); + } + } + else + { + int new_ip; + + if ( get_ip_one_line_above( text, text->ip1, &new_ip ) ) + { + if ( ep->v.character.shift ) + text->ip1 = new_ip; + else + text->selection_start_ip = text->ip1 = text->ip2 = new_ip; + if ( redisplay ) + display_if_necessary( text, TRUE ); + } else if ( text->ip1 != text->ip2 && !ep->v.character.shift ) + { + text->selection_start_ip = text->ip2 = text->ip1; + if ( redisplay ) + display_if_necessary( text, TRUE ); + } + } + return TRUE; +} + +static void +key_page_up( XI_TEXT * text, XinEvent * ep ) +{ + int cnt; + + if ( !text->multi_line ) + return; + for ( cnt = 0; cnt < text->max_lines_to_draw; ++cnt ) + key_up( text, ep, FALSE ); + display_if_necessary( text, TRUE ); +} + +static BOOLEAN +get_ip_one_line_below( XI_TEXT * text, int ip, int *new_ip ) +{ + int line, + pix_len; + char *s; + char *pls; + + line = get_line_from_ip( text, ip ); + if ( line < text->nbr_lines - 1 ) + { + int cnt, + len; + + s = get_line( text, line, NULL ); + pix_len = XinFontTextWidthGet( text->font, s, ip - text->line_breaks[line].line_break ); + pls = get_line( text, line + 1, &len ); + for ( cnt = 0; cnt < len; ++cnt ) + { + int lpix_len; + + lpix_len = XinFontTextWidthGet( text->font, pls, cnt ); + if ( lpix_len >= pix_len ) + { + *new_ip = text->line_breaks[line + 1].line_break + cnt; + return TRUE; + } + } + *new_ip = text->line_breaks[line + 1].line_break + cnt - 1; + if ( line + 1 == text->nbr_lines - 1 ) + ++* new_ip; + return TRUE; + } + return FALSE; +} + +static BOOLEAN +key_down( XI_TEXT * text, XinEvent * ep, BOOLEAN redisplay ) +{ + if ( !text->multi_line ) + return FALSE; + if ( text->ip1 == text->ip2 ) + { + int new_ip; + + if ( get_ip_one_line_below( text, text->ip1, &new_ip ) ) + { + if ( ep->v.character.shift ) + { + text->ip2 = new_ip; + text->selection_start_ip = text->ip1; + } + else + text->selection_start_ip = text->ip1 = text->ip2 = new_ip; + if ( redisplay ) + display_if_necessary( text, TRUE ); + } + return TRUE; + } + if ( text->selection_start_ip == text->ip2 ) + { + int new_ip; + + if ( get_ip_one_line_below( text, text->ip1, &new_ip ) ) + { + if ( ep->v.character.shift ) + { + text->ip1 = new_ip; + if ( text->ip2 < text->ip1 ) + { + int temp; + + temp = text->ip1; + text->ip1 = text->ip2; + text->ip2 = temp; + text->selection_start_ip = text->ip1; + } + } + else + text->selection_start_ip = text->ip1 = text->ip2 = new_ip; + if ( redisplay ) + display_if_necessary( text, TRUE ); + } + } + else + { + int new_ip; + + if ( get_ip_one_line_below( text, text->ip2, &new_ip ) ) + { + if ( ep->v.character.shift ) + text->ip2 = new_ip; + else + text->selection_start_ip = text->ip1 = text->ip2 = new_ip; + if ( redisplay ) + display_if_necessary( text, TRUE ); + } else if ( text->ip1 != text->ip2 && !ep->v.character.shift ) + { + text->selection_start_ip = text->ip1 = text->ip2; + if ( redisplay ) + display_if_necessary( text, TRUE ); + } + } + return TRUE; +} + +static void +key_page_down( XI_TEXT * text, XinEvent * ep ) +{ + int cnt; + + if ( !text->multi_line ) + return; + for ( cnt = 0; cnt < text->max_lines_to_draw; ++cnt ) + key_down( text, ep, FALSE ); + display_if_necessary( text, TRUE ); +} + +static void +key_line_home( XI_TEXT * text, XinEvent * ep ) +{ + if ( text->multi_line ) + { + if ( text->ip1 == text->ip2 ) + { + int home_ip, + line; + + line = get_line_from_ip( text, text->ip1 ); + home_ip = text->line_breaks[line].line_break; + if ( ep->v.character.shift ) + { + text->ip1 = home_ip; + text->selection_start_ip = text->ip2; + } + else + text->selection_start_ip = text->ip1 = text->ip2 = home_ip; + } + else + { + if ( text->selection_start_ip == text->ip1 ) + { + int home_ip, + line; + + line = get_line_from_ip( text, text->ip2 ); + home_ip = text->line_breaks[line].line_break; + if ( ep->v.character.shift ) + { + text->ip2 = home_ip; + if ( text->ip2 < text->ip1 ) + { + int temp; + + temp = text->ip1; + text->ip1 = text->ip2; + text->ip2 = temp; + text->selection_start_ip = text->ip1; + } + } + else + text->selection_start_ip = text->ip1 = text->ip2 = home_ip; + } + else + { + int home_ip, + line; + + line = get_line_from_ip( text, text->ip1 ); + home_ip = text->line_breaks[line].line_break; + if ( ep->v.character.shift ) + text->ip1 = home_ip; + else + text->selection_start_ip = text->ip1 = text->ip2 = home_ip; + } + } + } + else + { + if ( text->ip1 == text->ip2 ) + { + if ( ep->v.character.shift ) + { + text->ip1 = 0; + text->selection_start_ip = text->ip2; + } + else + text->selection_start_ip = text->ip1 = text->ip2 = 0; + } + else + { + if ( text->selection_start_ip == text->ip1 ) + { + if ( ep->v.character.shift ) + { + text->ip2 = 0; + if ( text->ip2 < text->ip1 ) + { + int temp; + + temp = text->ip1; + text->ip1 = text->ip2; + text->ip2 = temp; + text->selection_start_ip = text->ip1; + } + } + else + text->selection_start_ip = text->ip1 = text->ip2 = 0; + } + else + { + if ( ep->v.character.shift ) + text->ip1 = 0; + else + text->selection_start_ip = text->ip1 = text->ip2 = 0; + } + } + } + display_if_necessary( text, TRUE ); +} + +static void +key_line_end( XI_TEXT * text, XinEvent * ep ) +{ + if ( text->multi_line ) + { + if ( text->ip1 == text->ip2 ) + { + int end_ip, + line, + len; + + line = get_line_from_ip( text, text->ip1 ); + get_line( text, line, &len ); + end_ip = text->line_breaks[line].line_break + len - 1; + if ( line == text->nbr_lines - 1 ) + ++end_ip; + if ( ep->v.character.shift ) + { + text->ip2 = end_ip; + text->selection_start_ip = text->ip1; + } + else + text->selection_start_ip = text->ip1 = text->ip2 = end_ip; + } + else + { + if ( text->selection_start_ip == text->ip1 ) + { + int end_ip, + line, + len; + + line = get_line_from_ip( text, text->ip2 ); + get_line( text, line, &len ); + end_ip = text->line_breaks[line].line_break + len - 1; + if ( line == text->nbr_lines - 1 ) + ++end_ip; + if ( ep->v.character.shift ) + text->ip2 = end_ip; + else + text->selection_start_ip = text->ip1 = text->ip2 = end_ip; + } + else + { + int end_ip, + line, + len; + + line = get_line_from_ip( text, text->ip2 ); + get_line( text, line, &len ); + if ( line == text->nbr_lines - 1 ) + end_ip = text->line_breaks[line].line_break + len; + else + end_ip = text->line_breaks[line].line_break + len - 1; + if ( ep->v.character.shift ) + { + text->ip1 = end_ip; + if ( text->ip2 < text->ip1 ) + { + int temp; + + temp = text->ip1; + text->ip1 = text->ip2; + text->ip2 = temp; + text->selection_start_ip = text->ip1; + } + } + else + text->selection_start_ip = text->ip1 = text->ip2 = end_ip; + } + } + } + else + { + if ( text->ip1 == text->ip2 ) + { + int end_ip; + + end_ip = strlen( text->string ); + if ( ep->v.character.shift ) + { + text->ip2 = end_ip; + text->selection_start_ip = text->ip1; + } + else + text->selection_start_ip = text->ip1 = text->ip2 = end_ip; + } + else + { + if ( text->selection_start_ip == text->ip1 ) + { + int end_ip; + + end_ip = strlen( text->string ); + if ( ep->v.character.shift ) + text->ip2 = end_ip; + else + text->selection_start_ip = text->ip1 = text->ip2 = end_ip; + } + else + { + int end_ip; + + end_ip = strlen( text->string ); + if ( ep->v.character.shift ) + { + text->ip1 = end_ip; + if ( text->ip2 < text->ip1 ) + { + int temp; + + temp = text->ip1; + text->ip1 = text->ip2; + text->ip2 = temp; + text->selection_start_ip = text->ip1; + } + } + else + text->selection_start_ip = text->ip1 = text->ip2 = end_ip; + } + } + } + display_if_necessary( text, TRUE ); +} + +static int +get_ip_one_word_left( XI_TEXT * text, int ip ) +{ + int line = 0; + + if ( text->multi_line ) + { + line = get_line_from_ip( text, ip ); + if ( ip == text->line_breaks[line].line_break ) + { + int len; + + if ( line == 0 ) + return ip; + --line; + get_line( text, line, &len ); + return text->line_breaks[line].line_break + len - 1; + } + } + + if ( !text->multi_line ) + { + if ( ip == 0 ) + return ip; + } + /* move back one character, to get away from the beginning of a word */ + --ip; + /* find the first character that is not white space */ + while ( TRUE ) + { + if ( text->multi_line ) + { + if ( ip == text->line_breaks[line].line_break ) + return ip; + } + else + { + if ( ip == 0 ) + return ip; + } + if ( is_word_char( text->string[ip] ) ) + { + /* find the first character that is white space */ + while ( TRUE ) + { + if ( text->multi_line ) + { + if ( ip == text->line_breaks[line].line_break ) + return ip; + } + else + { + if ( ip == 0 ) + return ip; + } + if ( !is_word_char( text->string[ip] ) ) + return ip; + --ip; + } + } + --ip; + } +} + +static void +key_word_left( XI_TEXT * text, XinEvent * ep ) +{ + if ( text->ip1 == text->ip2 ) + { + int left_ip; + + left_ip = get_ip_one_word_left( text, text->ip1 ); + if ( ep->v.character.shift ) + { + text->ip1 = left_ip; + text->selection_start_ip = text->ip2; + } + else + text->selection_start_ip = text->ip1 = text->ip2 = left_ip; + } + else + { + if ( text->selection_start_ip == text->ip1 ) + { + int left_ip; + + left_ip = get_ip_one_word_left( text, text->ip2 ); + if ( ep->v.character.shift ) + { + text->ip2 = left_ip; + if ( text->ip2 < text->ip1 ) + { + int temp; + + temp = text->ip1; + text->ip1 = text->ip2; + text->ip2 = temp; + text->selection_start_ip = text->ip2; + } + } + else + text->selection_start_ip = text->ip1 = text->ip2 = left_ip; + } + else + { + int left_ip; + + left_ip = get_ip_one_word_left( text, text->ip1 ); + if ( ep->v.character.shift ) + text->ip1 = left_ip; + else + text->selection_start_ip = text->ip1 = text->ip2 = left_ip; + } + } + display_if_necessary( text, TRUE ); +} + +static int +get_ip_one_word_right( XI_TEXT * text, int ip ) +{ + int line = 0, + len, + string_len; + + if ( text->multi_line ) + { + line = get_line_from_ip( text, ip ); + get_line( text, line, &len ); + if ( ip == text->line_breaks[line].line_break + len ) + { + if ( line == text->nbr_lines - 1 ) + return ip; + ++line; + return text->line_breaks[line].line_break; + } + } + + string_len = strlen( text->string ); + while ( TRUE ) + { + if ( text->multi_line ) + { + if ( ip == text->line_breaks[line].line_break + len ) + return ip; + } + else + { + if ( ip == string_len ) + return ip; + } + if ( is_word_char( text->string[ip] ) ) + { + while ( TRUE ) + { + if ( text->multi_line ) + { + if ( ip == text->line_breaks[line].line_break + len ) + return ip; + } + else + { + if ( ip == string_len ) + return ip; + } + if ( !is_word_char( text->string[ip] ) ) + { + while ( TRUE ) + { + if ( text->multi_line ) + { + if ( ip == text->line_breaks[line].line_break + len ) + return ip; + } + else + { + if ( ip == string_len ) + return ip; + } + if ( is_word_char( text->string[ip] ) ) + return ip; + ++ip; + } + } + ++ip; + } + } + ++ip; + } +} + +static void +key_word_right( XI_TEXT * text, XinEvent * ep ) +{ + if ( text->ip1 == text->ip2 ) + { + int right_ip; + + right_ip = get_ip_one_word_right( text, text->ip1 ); + if ( ep->v.character.shift ) + { + text->ip2 = right_ip; + text->selection_start_ip = text->ip1; + } + else + text->selection_start_ip = text->ip1 = text->ip2 = right_ip; + } + else + { + if ( text->selection_start_ip == text->ip2 ) + { + int right_ip; + + right_ip = get_ip_one_word_right( text, text->ip1 ); + if ( ep->v.character.shift ) + { + text->ip1 = right_ip; + if ( text->ip2 < text->ip1 ) + { + int temp; + + temp = text->ip1; + text->ip1 = text->ip2; + text->ip2 = temp; + text->selection_start_ip = text->ip1; + } + } + else + text->selection_start_ip = text->ip1 = text->ip2 = right_ip; + } + else + { + int right_ip; + + right_ip = get_ip_one_word_right( text, text->ip2 ); + if ( ep->v.character.shift ) + text->ip2 = right_ip; + else + text->selection_start_ip = text->ip1 = text->ip2 = right_ip; + } + } + display_if_necessary( text, TRUE ); +} + +static void +delete_selection( XI_TEXT * text, BOOLEAN redisplay ) +{ + memmove( &text->string[text->ip1], + &text->string[text->ip2], + strlen( text->string ) - text->ip2 + 1 ); + text->selection_start_ip = text->ip2 = text->ip1; + if ( redisplay ) + display_if_necessary( text, TRUE ); +} + +static void +key_backspace( XI_TEXT * text, BOOLEAN * changed ) +{ + if ( text->ip1 == text->ip2 ) + { + if ( text->ip1 >= 1 ) + { + memmove( &text->string[text->ip1 - 1], + &text->string[text->ip1], + strlen( text->string ) - text->ip1 + 1 ); + text->selection_start_ip = text->ip2 = --text->ip1; + display_if_necessary( text, TRUE ); + if ( changed ) + *changed = TRUE; + } + else + { + if ( changed ) + *changed = FALSE; + } + } + else + { + delete_selection( text, TRUE ); + if ( changed ) + *changed = TRUE; + } +} + +static void +key_delete( XI_TEXT * text, BOOLEAN * changed ) +{ + if ( text->ip1 == text->ip2 ) + { + int len; + + len = strlen( text->string ); + if ( text->ip2 <= len - 1 ) + { + memmove( &text->string[text->ip2], + &text->string[text->ip2 + 1], + len - text->ip2 + 1 ); + display_if_necessary( text, TRUE ); + if ( changed ) + *changed = TRUE; + } + else + { + if ( changed ) + *changed = FALSE; + } + } + else + { + delete_selection( text, TRUE ); + if ( changed ) + *changed = TRUE; + } +} + +static BOOLEAN +key_character( XI_TEXT * text, XinEvent * ep, BOOLEAN * changed ) +{ + int len; + int ch; + + if ( changed ) + *changed = FALSE; + if ( ep->v.character.ch > 255 ) + return FALSE; + if ( ep->v.character.ch == '\r' || ep->v.character.ch == '\n' ) + { + if ( !text->cr_ok || text->read_only ) + return FALSE; + } + else if ( ep->v.character.ch < 128 && !isprint( ep->v.character.ch ) ) + return FALSE; + + ch = ep->v.character.ch; + if ( ch == '\r' ) + ch = '\n'; + len = strlen( text->string ); + if ( text->ip1 != text->ip2 ) + { + delete_selection( text, FALSE ); + if ( changed ) + *changed = TRUE; + } + len = strlen( text->string ); + if ( text->var_len_text || ( ( int ) len < text->buffer_size - 1 ) ) + { + if (text->var_len_text) + reallocate_text( text, len + 2, FALSE ); + memmove( &text->string[text->ip1 + 1], + &text->string[text->ip1], + len - text->ip1 + 1 ); + text->string[text->ip1] = ch; + text->selection_start_ip = text->ip1 = ++text->ip2; + if ( changed ) + *changed = TRUE; + if ( len + 2 > text->buffer_size ) + text->buffer_size = len + 2; + } + display_if_necessary( text, TRUE ); + return TRUE; +} + +/* +this function is changes delta_y when the user operates the scroll bar on a +multi-line edit control. + +this function is only used for multi_line edit controls. +*/ +static void +move_delta( XI_TEXT * text, int nbr_lines ) +{ + if ( nbr_lines < 0 ) + { + nbr_lines = -nbr_lines; + if ( text->delta_y >= nbr_lines ) + text->delta_y -= nbr_lines; + else + text->delta_y = 0; + } + else + { + if ( text->delta_y + nbr_lines < text->nbr_lines - text->max_lines_to_draw ) + text->delta_y += nbr_lines; + else + { + text->delta_y = text->nbr_lines - text->max_lines_to_draw; + if ( text->delta_y < 0 ) + text->delta_y = 0; + } + } + display_if_necessary( text, FALSE ); +} + +/* +this function is changes delta_y when the user operates the scroll bar on a +multi-line edit control. + +this function is only used for multi_line edit controls. +*/ +static void +set_pos_delta( XI_TEXT * text, int pos, int prop ) +{ + int new_pos; + + new_pos = ( int ) ( ( ( double ) text->nbr_lines - ( double ) text->max_lines_to_draw ) * + ( double ) pos / ( double ) ( 1000 - prop ) ); + if ( new_pos < 0 ) + new_pos = 0; + text->delta_y = new_pos; + display_if_necessary( text, FALSE ); +} + +static int +xi_text_point_hit_test( XinFont * font, char *str, int hpos, int last_ip, int del_x ) +{ + int left_point, + right_point; + int x1, + x2, + x3; + + if ( hpos == 0 ) + { + left_point = 0; + x1 = XinFontTextWidthGet( font, str, 1 ); + right_point = x1 / 2; + } + else + { + x1 = XinFontTextWidthGet( font, str, hpos - 1 ); + x2 = XinFontTextWidthGet( font, &str[hpos - 1], 1 ); + left_point = x1 + x2 / 2 + 1; + if ( hpos == last_ip ) + right_point = x1 + x2; + else + { + x3 = XinFontTextWidthGet( font, &str[hpos], 1 ); + right_point = x1 + x2 + x3 / 2; + } + } + if ( del_x < left_point ) + return -1; + else if ( del_x > right_point ) + return 1; + else + return 0; +} + +/* +this function returns an insertion point, given an XinEvent. + +this function works by doing a binary search. +*/ +static void +xi_text_hit_test( XI_TEXT * text, XinEvent * ep, int *ip ) +{ + int del_y, + del_x, + line = 0, + len, + cnt, + last_ip; + int hpos, + d, + delta_x_pix, + max_str_len; + char *str; + + if ( text->multi_line ) + { + if ( ep->v.mouse.where.v < text->prect.top ) + { + int lines_above; + + lines_above = ( text->prect.top - ep->v.mouse.where.v ) / text->font_height + 1; + line = text->delta_y - lines_above; + if ( line < 0 ) + line = 0; + } + else + { + del_y = ep->v.mouse.where.v - text->prect.top; + line = del_y / text->font_height + text->delta_y; + if ( line >= text->nbr_lines ) + line = text->nbr_lines - 1; + } + str = get_line( text, line, &len ); + delta_x_pix = XinFontTextWidthGet( text->font, str, text->delta_x ); + del_x = ep->v.mouse.where.h - text->prect.left + delta_x_pix; + } + else + { + len = strlen( text->string ); + if ( text->password ) + str = alloc_password_string( len, text ); + else + str = text->string; + if ( text->right_justify ) + { + /* calculate del_x. del_x is the distance in pixels from the virtual + * beginning of the right justified text to the horizontal position of + * the mouse. the code below works just fine if del_x is negative: ie if + * the mouse is to the left of the right justified text. */ + int str_len_in_pix; + + delta_x_pix = XinFontTextWidthGet( text->font, + &str[len - text->delta_x], text->delta_x ); + str_len_in_pix = XinFontTextWidthGet( text->font, str, -1 ); + del_x = ep->v.mouse.where.h - ( text->prect.right - str_len_in_pix + + delta_x_pix ); + } + else + { + /* calculate del_x. del_x is the distance in pixels from the virtual + * beginning of the left justified text to the horizontal position of the + * mouse. the code below works just fine if del_x is negative: ie if the + * mouse is to the left of the text. */ + delta_x_pix = XinFontTextWidthGet( text->font, str, text->delta_x ); + del_x = ep->v.mouse.where.h - text->prect.left + delta_x_pix; + } + } + + /* binary search - find cnt where the mathmatical line between characters is + * closest to pix_len. + * + * this binary search uses a deterministic algorythm. by this, when starting + * searching, hpos is always a power of 2. d is the delta that is added to + * or subtracted from hpos after each comparison. d is initialized as hpos / + * 2. therefore, d is *always* a power of 2. */ + + /* last_ip = len + 1, because there is one more possible insertion point than + * characters */ + last_ip = len + 1; + hpos = 1; + while ( hpos <= last_ip ) + hpos = hpos << 1; + d = hpos / 2; + --hpos; + if ( del_x < 0 ) + del_x = 0; + max_str_len = XinFontTextWidthGet( text->font, str, len ); + if ( del_x > max_str_len ) + del_x = max_str_len; + while ( TRUE ) + { + int result; + + if ( hpos > len ) + { + if ( d == 0 ) + { + cnt = len; + break; + } + hpos -= d; + d /= 2; + continue; + } + result = xi_text_point_hit_test( text->font, str, hpos, last_ip, del_x ); + if ( result == 0 ) + { + cnt = hpos; + break; + } + if ( result < 0 ) + { + hpos -= d; + d /= 2; + } + else + { + hpos += d; + d /= 2; + } + } + if ( text->multi_line ) + *ip = text->line_breaks[line].line_break + cnt; + else + *ip = cnt; + if ( text->password ) + xi_tree_free( str ); +} + +/* +only used if multi_line, and if there is a scroll bar. +*/ +void +xi_text_control_event( XI_TEXT * text, XinEvent * ep ) +{ + save_text_state( text ); + + switch ( ep->v.control.ctrl_info.v.scroll.action ) + { + case XinScrollBarActionLineUp: + move_delta( text, -1 ); + break; + case XinScrollBarActionLineDown: + move_delta( text, 1 ); + break; + case XinScrollBarActionPageUp: + move_delta( text, -text->max_lines_to_draw ); + break; + case XinScrollBarActionPageDown: + move_delta( text, text->max_lines_to_draw ); + break; + case XinScrollBarActionThumb: + case XinScrollBarActionThumbTrack: + { + int percent = ep->v.control.ctrl_info.v.scroll.position; + int prop = XinScrollBarProportionGet( text->sb_win, XinScrollBarTypeEither ); + + set_pos_delta( text, percent, prop ); + break; + } + default: + break; + } + if ( save_text ) + free_save_text_state( ); +} + +/* +xi_text_character_event, xi_text_mouse_down_event, xi_text_mouse_double_event, +xi_text_mouse_move_event, and xi_text_mouse_up_event don't care whether the +xi_text is single or multi_line, or if it is right justified. +*/ +BOOLEAN +xi_text_character_event( XI_TEXT * text, XinEvent * ep, BOOLEAN * changed ) +{ + BOOLEAN retval; + + save_text_state( text ); + switch ( ep->v.character.ch ) + { + case XI_KEY_LEFT: + key_left( text, ep ); + retval = TRUE; + break; + case XI_KEY_RIGHT: + key_right( text, ep ); + retval = TRUE; + break; + case XI_KEY_UP: + retval = key_up( text, ep, TRUE ); + break; + case XI_KEY_DOWN: + retval = key_down( text, ep, TRUE ); + break; + case XI_KEY_PREV: + key_page_up( text, ep ); + retval = TRUE; + break; + case XI_KEY_NEXT: + key_page_down( text, ep ); + retval = TRUE; + break; + case XI_KEY_LHOME: + case XI_KEY_HOME: + key_line_home( text, ep ); + retval = TRUE; + break; + case XI_KEY_LEND: + case XI_KEY_END: + key_line_end( text, ep ); + retval = TRUE; + break; + case XI_KEY_WLEFT: + key_word_left( text, ep ); + retval = TRUE; + break; + case XI_KEY_WRIGHT: + key_word_right( text, ep ); + retval = TRUE; + break; + case '\b': + if ( !text->read_only ) + key_backspace( text, changed ); + retval = TRUE; + break; + case XI_KEY_DEL: + if ( !text->read_only ) + key_delete( text, changed ); + retval = TRUE; + break; + case XI_KEY_F3: + case XI_KEY_F4: + retval = key_character( text, ep, changed ); // Added by AGA + break; + default: + if ( text->read_only ) + { + if ( ep->v.character.ch == '\033' || + ep->v.character.ch == '\r' || + ep->v.character.ch == '\n' ) + { + if ( save_text ) + free_save_text_state( ); + return FALSE; + } + if ( (ep->v.character.ch != '\r' && ep->v.character.ch != '\n') + || !text->itf->v.itf->tab_on_enter ) + { + if ( save_text ) + free_save_text_state( ); + return TRUE; + } + } + retval = key_character( text, ep, changed ); + break; + } + if ( save_text ) + free_save_text_state( ); + return retval; +} + +void +xi_text_mouse_down_event( XI_TEXT * text, XinEvent * ep, BOOLEAN gaining_focus ) +{ + int ip; + + if ( text->timer_set ) + { + XinWindowTimerKill( text->win, text->timer_id ); + text->timer_set = FALSE; + text->timer_id = 0; + xi_text_selection_set( text, 0, 32000 ); + return; + } + if ( gaining_focus && ( text->parent_obj == 0 || + ( xi_get_attrib( text->parent_obj ) & XI_ATR_AUTOSELECT ) ) && + xi_get_pref( XI_PREF_AUTOSEL_ON_MOUSE ) ) + { + xi_text_selection_set( text, 0, INT_MAX ); + return; + } + xi_text_hit_test( text, ep, &ip ); + if ( ep->v.mouse.shift ) + { + if ( text->selection_start_ip == text->ip1 ) + xi_text_selection_set_internal( text, text->ip1, ip, text->ip1, TRUE, FALSE ); + else + xi_text_selection_set_internal( text, ip, text->ip2, text->ip2, TRUE, FALSE ); + } + else + xi_text_selection_set_internal( text, ip, ip, ip, TRUE, FALSE ); + XinWindowMouseTrap( text->win, TRUE ); + text->selecting = TRUE; +} + +void +xi_text_mouse_double_event( XI_TEXT * text, XinEvent * ep ) +{ + int ip, + right_ip, + left_ip; + long time; + + xi_text_hit_test( text, ep, &ip ); + right_ip = get_ip_one_word_right( text, ip ); + if ( text->string[right_ip - 1] == ' ' ) + --right_ip; + left_ip = get_ip_one_word_left( text, ip ); + if ( text->string[left_ip] == ' ' ) + ++left_ip; + xi_text_selection_set_internal( text, left_ip, right_ip, left_ip, TRUE, FALSE ); + XinWindowMouseTrap( text->win, TRUE ); + text->double_selecting = TRUE; + text->double_selecting_start_ip = ip; + time = xi_get_pref( XI_PREF_TRIPLE_CLICK_TIME ); + if ( time ) + { + text->timer_id = XinWindowTimerSet( text->win, time ); + text->timer_set = TRUE; + } +} + +void +xi_text_mouse_move_event( XI_TEXT * text, XinEvent * ep ) +{ + int ip; + + if ( text->selecting ) + { + xi_text_hit_test( text, ep, &ip ); + if ( ip < text->selection_start_ip ) + xi_text_selection_set_internal( text, ip, text->selection_start_ip, + text->selection_start_ip, TRUE, FALSE ); + else + xi_text_selection_set_internal( text, text->selection_start_ip, ip, + text->selection_start_ip, TRUE, FALSE ); + } + if ( text->double_selecting ) + { + xi_text_hit_test( text, ep, &ip ); + if ( ip < text->double_selecting_start_ip ) + { + int left_ip, + right_ip; + + left_ip = get_ip_one_word_left( text, ip ); + if ( text->string[left_ip] == ' ' ) + ++left_ip; + right_ip = get_ip_one_word_right( text, text->double_selecting_start_ip ); + if ( text->string[right_ip - 1] == ' ' ) + --right_ip; + xi_text_selection_set_internal( text, left_ip, right_ip, + right_ip, TRUE, FALSE ); + } + else + { + int left_ip, + right_ip; + + right_ip = get_ip_one_word_right( text, ip ); + if ( text->string[right_ip - 1] == ' ' ) + --right_ip; + left_ip = get_ip_one_word_left( text, text->double_selecting_start_ip ); + if ( text->string[left_ip] == ' ' ) + ++left_ip; + xi_text_selection_set_internal( text, left_ip, right_ip, + left_ip, TRUE, FALSE ); + } + } +} + +void +xi_text_mouse_up_event( XI_TEXT * text, XinEvent * ep ) +{ + int ip; + + if ( text->selecting ) + { + xi_text_hit_test( text, ep, &ip ); + if ( ip < text->selection_start_ip ) + xi_text_selection_set_internal( text, ip, text->selection_start_ip, + text->selection_start_ip, TRUE, FALSE ); + else + xi_text_selection_set_internal( text, text->selection_start_ip, ip, + text->selection_start_ip, TRUE, FALSE ); + XinWindowMouseRelease( ); + text->selecting = FALSE; + } + if ( text->double_selecting ) + { + XinWindowMouseRelease( ); + text->double_selecting = FALSE; + } +} + +void +xi_text_timer_event( XI_TEXT * text, XinEvent * ep ) +{ + if ( ep->v.timer.id == text->timer_id ) + { + XinWindowTimerKill( text->win, ep->v.timer.id ); + text->timer_id = 0; + text->timer_set = FALSE; + } +} + +/* +all events are passed to this function. +*/ +BOOLEAN +xi_text_event( XI_TEXT * text, XinEvent * ep, BOOLEAN gaining_focus, BOOLEAN * changed ) +{ + BOOLEAN retval = FALSE; + + if ( changed ) + *changed = FALSE; + text = text; + if ( !text ) + return retval; + switch ( ep->type ) + { + case XinEventControl: + xi_text_control_event( text, ep ); + break; + case XinEventCharacter: + retval = xi_text_character_event( text, ep, changed ); + break; + case XinEventPaint: + xi_text_draw( text, 0L, 0L, TRUE ); + break; + case XinEventMouseDown: + xi_text_mouse_down_event( text, ep, gaining_focus ); + break; + case XinEventMouseDouble: + xi_text_mouse_double_event( text, ep ); + break; + case XinEventMouseMove: + xi_text_mouse_move_event( text, ep ); + break; + case XinEventMouseUp: + xi_text_mouse_up_event( text, ep ); + break; + case XinEventTimer: + xi_text_timer_event( text, ep ); + break; + default: + break; + } + return retval; +} + +/* +this stops editing for an xi_text. +*/ +void +xi_text_editing_stop( XI_TEXT * text ) +{ + if ( text->editing == FALSE ) + return; + xi_text_caret_off( text ); + xi_text_selection_set_internal( text, 0, 0, 0, FALSE, TRUE ); + text->editing = FALSE; + if ( text->sb_win && !text->scrollbar_always_visible ) + { + if ( !xi_itf_in_event_destroy( text->itf ) ) + XinWindowDestroy( text->sb_win ); + text->sb_win = XI_NULL_WINDOW; + } + if ( save_text ) + free_save_text_state( ); +} + + +/* +this function sets the physical rectangle for an xi_text. +*/ +void +xi_text_prect_set( XI_TEXT * text, XinRect * rctp ) +{ + int pix_width; + BOOLEAN changed = FALSE; + + if ( text->prect.top != rctp->top || text->prect.bottom != rctp->bottom || + text->prect.left != rctp->left || text->prect.right != rctp->right ) + changed = TRUE; + + text->prect = *( rctp ); + if ( text->font_height == 0 ) + { + XinFont *font; + int char_width; + + font = text->font; + xi_get_font_metrics_font( font, &text->leading, &text->ascent, &text->descent, &char_width ); + text->font_height = text->ascent + text->descent + text->leading; + } + text->max_lines_to_draw = ( rctp->bottom - rctp->top ) / text->font_height; + if ( text->max_lines_to_draw < 1 ) + text->max_lines_to_draw = 1; + pix_width = rctp->right - rctp->left; + text->pix_width = pix_width; + if ( text->scrollbar ) + { + if ( !text->sb_width ) + text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth ); + text->internal_pix_width = text->pix_width - text->sb_width - SB_DELTA; + if ( changed && ( text->scrollbar_always_visible || text->sb_win ) ) + { + XinWindowDef Def; + XinRect rct; + + MEMCLEAR( Def ); + Def.control_id = text->cid; + Def.type = XinWindowTypeVerticalScrollBar; + rct.top = text->prect.top; + rct.bottom = text->prect.bottom; + rct.right = text->prect.left + text->internal_pix_width + SB_DELTA + text->sb_width; + rct.left = text->prect.left + text->internal_pix_width + SB_DELTA; + Def.p_rect = &rct; + Def.title = ""; + Def.visible = text->visible; + Def.enabled = TRUE; + Def.parent = text->win; + if ( text->sb_win != XI_NULL_WINDOW ) + XinWindowDestroy( text->sb_win ); + text->sb_win = XinWindowCreate( &Def ); + } + } + else + text->internal_pix_width = text->pix_width; +} + +XI_TEXT * +xi_text_focus_get( XinWindow win ) +{ + XI_OBJ *itf, + *focus_obj; + + itf = xi_get_itf( win ); + focus_obj = xi_get_focus( itf ); + if ( focus_obj ) + { + switch ( focus_obj->type ) + { + case XIT_CELL: + return lm_xi_text_focus_get( focus_obj->parent->v.list->lm ); + case XIT_FIELD: + return stx_xi_text_get( focus_obj->v.field->stx ); + default: + return NULL; + } + } + return NULL; +} + +void +xi_text_buffer_size_set( XI_TEXT * text, int len ) +{ + int ip1 = 0, ip2 = 0, sip = 0; + BOOLEAN reset_ips = FALSE; + + if ( xi_text_editing_is( text ) ) + { + ip1 = text->ip1; + ip2 = text->ip2; + sip = text->selection_start_ip; + reset_ips = TRUE; + } + if ( len < text->buffer_size ) + text->initialized = FALSE; + text->buffer_size = len; + reallocate_text( text, len, TRUE ); + xi_text_wrap( text ); + if ( reset_ips ) + { + ip1 = min( ip1, len - 1 ); + ip2 = min( ip2, len - 1 ); + sip = min( sip, len - 1 ); + xi_text_selection_set_internal( text, ip1, ip2, sip, TRUE, TRUE ); + } +} + +void +xi_text_font_set( XI_TEXT * text, XinFont * font ) +{ + int char_width; + BOOLEAN restart = FALSE; + + if ( xi_text_editing_is( text ) ) + { + xi_text_editing_stop( text ); + restart = TRUE; + } + text->font = font; + xi_get_font_metrics_font( font, &text->leading, &text->ascent, &text->descent, &char_width ); + text->font_height = text->ascent + text->descent + text->leading; + text->max_lines_to_draw = ( text->prect.bottom - text->prect.top ) / text->font_height; + if ( text->max_lines_to_draw < 1 ) + text->max_lines_to_draw = 1; + if ( text->multi_line ) + xi_text_wrap_internal( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + if ( restart ) + xi_text_editing_start( text ); +} + +void +xi_text_visible_set( XI_TEXT * text, BOOLEAN visible ) +{ + text->visible = visible; + if ( text->sb_win ) + { + XinWindowShow( text->sb_win, visible ); + } +} + +XinRect * +xi_text_rect_get_adjusted( XI_TEXT * text, XinRect * rcta ) +{ + if ( text->scrollbar ) + { + if ( !text->sb_width ) + text->sb_width = ( int ) XinMetricGet( XinMetricVerticalScrollBarWidth ); + rcta->right = rcta->right - text->sb_width - SB_DELTA; + } + + return ( rcta ); +} + +void +xi_text_paste_internal( XI_TEXT * text, char *string ) +{ + int len, len2; + int cnt, + ip; + char *str; + + if ( text->read_only ) + return; + + if ( text->ip1 != text->ip2 ) + delete_selection( text, TRUE ); + + len = strlen( text->string ); + len2 = strlen( string ); + + str = xi_tree_malloc( len + len2 + 1, NULL ); + +/* New string in the middle */ + if ( text->ip1 > 0 && text->ip1 < len ) + { + gstrncpy( str, text->string, text->ip1 ); + strcat( str, string ); + ip = strlen( str ); + for ( cnt = text->ip1; cnt < len; ++cnt ) + { + str[ip] = text->string[cnt]; + ++ip; + } + } +/* there is nothing in the field, so simply use the string passed */ + else if ( len <= 0 ) + strcpy( str, string ); + else +/* New string at the end */ + if ( text->ip1 >= len ) + { + strcpy( str, text->string ); + strcat( str, string ); + } +/* New string at beginning */ + else + { + strcpy( str, string ); + strcat( str, text->string ); + } + + + len = reallocate_text( text, strlen( str ) + 1, FALSE ); + memcpy( text->string, str, len ); + xi_tree_free( str ); + + text->string[ len - 1 ] = '\0'; + + if ( text->ip2 > len - 1 ) + text->ip2 = len - 1; + if ( !text->editing ) + return; + XinWindowFontMap( text->win, text->font ); +/* + xi_text_caret_off( text ); + + if ( text->multi_line ) + { + xi_text_wrap_internal( text ); + recalc_line_ips( text ); + calc_delta_y( text ); + } + else + calc_delta_x( text ); + if ( text->sb_win ) + xi_text_sb_set( text ); + xi_text_draw_internal( text, 0L, 0L, FALSE ); + + xi_text_caret_on( text ); +*/ + display_if_necessary( text, TRUE ); +} + +void +xi_text_right_justify_set( XI_TEXT* text, BOOLEAN flag ) +{ + text->right_justify = flag; + if ( text->multi_line ) + text->right_justify = FALSE; +} + +/* }]) */ diff --git a/src/xi01/xitext.h b/src/xi01/xitext.h new file mode 100644 index 000000000..45d3cc0d6 --- /dev/null +++ b/src/xi01/xitext.h @@ -0,0 +1,132 @@ +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +/* +The font in the text may be just a copy of a font pointer that +is elsewhere, in which case, it will be freed when the interface +goes away. It also could be an instantiated copy of a font, in +which case, the font will have been put into the interface font list, +so that it will be freed when the interface goes away. +*/ + +typedef struct +{ + int line_break; + int ip1; /* -1 is null value */ + int ip2; /* -1 is null value */ + int active_ip; +} XI_TEXT_LINE_BREAK; + +typedef struct +{ + /* edit control info */ + char *string; /* current text of edit control */ + int pix_width; /* pix width as specified by user of text */ + int internal_pix_width; /* pix_width - scroll bar width - sb delta */ + int min_buffer_size; + int buffer_size; + int allocated_length; + BOOLEAN var_len_text; + int font_height; + int leading; + int ascent; + int descent; + XinFont *font; + XinWindow win; + XI_OBJ *parent_obj; + XinRect prect; /* physical rectangle of edit control */ + XinRect clip_rect; /* clipping is intersected with this rect */ + XinColor fore_color; + XinColor back_color; + XinColor fore_color_in_use; + XinColor back_color_in_use; + BOOLEAN multi_line; /* selection of multi or single line editing */ + BOOLEAN right_justify; /* selection of right or left justified text */ + BOOLEAN password; + BOOLEAN read_only; + BOOLEAN cr_ok; + + /* multiline edit control info */ + int nbr_lines; + XI_TEXT_LINE_BREAK *line_breaks; + int max_lines_to_draw; + BOOLEAN scrollbar; + XinWindow sb_win; + int sb_width; + int cid; /* used for scrollbar, same as parent's. */ + BOOLEAN scrollbar_always_visible; /* true for fields, false for cells. */ + XI_OBJ* itf; + BOOLEAN visible; + + /* editing state */ + BOOLEAN editing; + int selection_start_ip; + int ip1; + int ip2; + BOOLEAN selecting; + BOOLEAN double_selecting; + int double_selecting_start_ip; + BOOLEAN timer_set; + long timer_id; + BOOLEAN initialized; + + /* multiline editing state */ + int delta_y; /* number of lines scrolled vertically */ + + /* singleline editing state */ + int delta_x; /* number of characters scrolled horizontally */ +} XI_TEXT; + +#define xi_text_nbr_lines_get( text ) text->nbr_lines +#define xi_text_line_break_get( text, cnt ) ( text->line_breaks[ cnt ].line_break ) +#define xi_text_font_height_get( text ) text->font_height +#define xi_text_clip_set( text, rctp ) ( text->clip_rect = *(rctp)) +#define xi_text_max_lines_to_draw_set( text, max_lines_to_draw_arg ) ( text->max_lines_to_draw = max_lines_to_draw_arg ) +#define xi_text_color_fore_set( text, color ) ( text->fore_color = color ) +#define xi_text_color_back_set( text, color ) ( text->back_color = color ) +#define xi_text_get( text ) text->string +#define xi_text_parent_obj_set( text, obj ) ( text->parent_obj = obj ) +#define xi_text_scrollbar_set( text, has_scroll_bar ) ( text->scrollbar = has_scroll_bar ) +#define xi_text_password_set( text, is_pw ) ( text->password = is_pw ) +#define xi_text_read_only_set( text, flag ) ( text->read_only = flag ) +#define xi_text_editing_is( text ) text->editing +#define xi_text_buffer_set( text, buffer ) ( text->string = buffer ) +#define xi_text_cr_ok_set( text, is_ok ) ( text->cr_ok = is_ok ) +#define xi_text_initialized_set( text, set ) ( text->initialized = set ) +#define xi_text_buffer_size_get( text ) ( text->buffer_size ) +#define xi_text_min_buffer_size_set( text, set ) ( text->min_buffer_size = set ) +#define xi_text_var_len_text_set( text, set ) ( text->var_len_text = set ) +#define xi_text_font_get( text ) text->font + +void xi_text_set( XI_TEXT * text, const char *string ); +void xi_text_wrap( XI_TEXT * text ); +void xi_text_pix_width_set( XI_TEXT * text, int pix_width ); +void xi_text_pix_width_and_text_set( XI_TEXT * text, char *string, int pix_width, BOOLEAN set_font ); + +void xi_text_destruct( XI_TEXT * text ); +XI_TEXT *xi_text_construct( XinWindow win, int pix_width, XinFont * font, void *parent, + BOOLEAN multi_line, int cid, BOOLEAN scrollbar_always_visible ); +void xi_text_draw( XI_TEXT * text, XinColor color, XinColor back_color, BOOLEAN update ); +void xi_text_selection_set( XI_TEXT * text, int ip1, int ip2 ); +void xi_text_selection_get( XI_TEXT * text, int *ip1, int *ip2 ); +void xi_text_selection_get_internal( XI_TEXT * text, int *ip1, int *ip2, int *start_ip ); +void xi_text_selection_set_internal( XI_TEXT * text, int ip1, int ip2, + int selection_start_ip, BOOLEAN do_carets, BOOLEAN map_font ); +void xi_text_editing_start( XI_TEXT * text ); +void xi_text_editing_stop( XI_TEXT * text ); +BOOLEAN xi_text_event( XI_TEXT * text, XinEvent * ep, BOOLEAN gaining_focus, BOOLEAN *changed ); +void xi_text_prect_set( XI_TEXT * text, XinRect * rectp ); +XI_TEXT *xi_text_focus_get( XinWindow win ); +void xi_text_buffer_size_set( XI_TEXT* text, int size ); +void xi_text_font_set( XI_TEXT* text, XinFont* font ); +void xi_text_visible_set( XI_TEXT* text, BOOLEAN visible ); +XinRect* xi_text_rect_get_adjusted( XI_TEXT * text, XinRect * rcta ); +void xi_text_paste_internal( XI_TEXT * text, char *string ); +void xi_text_right_justify_set( XI_TEXT* text, BOOLEAN flag ); +void xi_text_reinitialize( XI_TEXT* text ); diff --git a/src/xi01/xitree.c b/src/xi01/xitree.c new file mode 100644 index 000000000..9058e7a2b --- /dev/null +++ b/src/xi01/xitree.c @@ -0,0 +1,506 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +/* ERROR CODES 20201-20201 */ + +#define XI_INTERNAL + +#include "xi.h" +#include "xiheap.h" +#include "xiutils.h" + +#define PADCHAR ((char)0x8e) +#define MAGIC 0xe8 + +/* + constants to define for more debugging + + PAD - pad allocations with N bytes of magic and check magic number when + xi_tree_check_sanity is called + FENCE - call xi_tree_check_sanity on every Nth xi_tree_* call + PREPAD - put an extra N bytes between the node struct and the data. + This padding is never checked. + + sample usage: + + #define PAD 20 + #define FENCE 10 + #define PREPAD 10 +*/ +/* +#define PAD 100 +#define FENCE 1 +*/ + +typedef struct _tree_node +{ + struct _tree_node *parent; + struct _tree_node *sibling; + struct _tree_node *child; +#ifdef TREEDEBUG + int line; + char *file; + int magic; /* for sanity checks */ + int size; +#ifdef PREPAD + char prepad[PREPAD]; +#endif +#endif +} TREE_NODE; + +/* This code automatically determines the proper size for TREE_NODE so that + the data following it is always correctly aligned. */ +static struct +{ + TREE_NODE node; + double data; +} dummy_header; + +#define SIZEOF_TREE_NODE ((int)( (char*)&dummy_header.data - (char*)&dummy_header.node )) + +#ifdef TREEDEBUG +#undef xi_tree_malloc +#undef xi_tree_realloc +#define xi_tree_malloc_body xi_tree_malloc_d +#define xi_tree_realloc_body xi_tree_realloc_d +#define xi_tree_malloc_stub xi_tree_malloc +#define xi_tree_realloc_stub xi_tree_realloc +#else +#define xi_tree_malloc_body xi_tree_malloc +#define xi_tree_realloc_body xi_tree_realloc +#define xi_tree_malloc_stub xi_tree_malloc_d +#define xi_tree_realloc_stub xi_tree_realloc_d +#endif + +#define VOIDPTR_TO_TREEPTR(p) ((TREE_NODE *)((long)(p) - SIZEOF_TREE_NODE)) +#define TREEPTR_TO_VOIDPTR(t) ((void *)((long)(t) + SIZEOF_TREE_NODE)) + +#define DBGTAB 3 + +static TREE_NODE topnode = +{ + NULL, &topnode, NULL +#ifdef TREEDEBUG + ,0, "TOPNODE", MAGIC, 0 +#endif +}; +static TREE_NODE *top = &topnode; + +#ifdef TREEDEBUG +#ifdef FENCE +static int fence_count; + +#endif +static int node_count = 1; /* start with just top node */ + +#endif + +static void +dflt_error_fcn( void ) +{ + NOREF( dummy_header.data ); + XinError( 20201, XinSeverityFatal, 0L ); +} + +static void ( *error_fcn ) ( void ) = dflt_error_fcn; + +#ifdef TREEDEBUG +void xi_tree_check_fence( void ); +void +xi_tree_check_fence( void ) +{ +#ifdef FENCE + static int fence_count; + + fence_count++; + if ( fence_count % FENCE == 0 ) + xi_tree_check_sanity( "FENCE CHECK" ); +#endif +} + +static void +adjust_size( size_t * size ) +{ + NOREF( size ); +#ifdef PAD + *size += PAD; +#endif +} + +static void +validate_node( void *p ) +{ + if ( p != NULL && VOIDPTR_TO_TREEPTR( p )->magic != MAGIC ) + XinDialogFatal( "Bad tree node detected: file %s, line %d", + VOIDPTR_TO_TREEPTR( p )->file, VOIDPTR_TO_TREEPTR( p )->line ); +} + +#endif + +static void +remove_from_siblings_and_parent( TREE_NODE * remove_t ) +{ + TREE_NODE *tp; + + /* remove from sibling list */ + tp = remove_t; + while ( tp->sibling != remove_t ) + tp = tp->sibling; + tp->sibling = remove_t->sibling; + + /* adjust parent pointers */ + if ( remove_t->parent->child == remove_t ) + { + remove_t->parent->child = ( ( remove_t->sibling == remove_t ) ? + NULL : remove_t->sibling ); + } +} + +static void +xi_tree_free_internal( TREE_NODE * remove_t, BOOLEAN toplevel ) +{ + TREE_NODE *tp; + TREE_NODE *nexttp; + + if ( toplevel ) + { + remove_from_siblings_and_parent( remove_t ); + remove_t->sibling = NULL; + } + + /* free all child nodes */ + tp = remove_t->child; + if ( tp != NULL ) + do + { + /* store next pointer before nuking node */ + nexttp = tp->sibling; + xi_tree_free_internal( tp, FALSE ); + tp = nexttp; + } while ( tp != remove_t->child ); + + /* free underlying heap manager memory */ +#ifdef TREEDEBUG + heap_free( remove_t->file ); + node_count--; +#endif + heap_free( remove_t ); +} + +void +xi_tree_reparent( void *p, void *parent ) +{ + TREE_NODE *tn; + +#ifdef TREEDEBUG + xi_tree_check_fence( ); + validate_node( p ); +#endif + remove_from_siblings_and_parent( VOIDPTR_TO_TREEPTR( p ) ); + tn = VOIDPTR_TO_TREEPTR( p ); + if ( parent == NULL ) + parent = TREEPTR_TO_VOIDPTR( top ); + tn->parent = VOIDPTR_TO_TREEPTR( parent ); + if ( tn->parent->child == NULL ) + { + tn->parent->child = tn; + tn->sibling = tn; + } + else + { + /* insert tn in the sibling list */ + tn->sibling = tn->parent->child->sibling; + tn->parent->child->sibling = tn; + } +} + +void +xi_tree_free( void *p ) +{ +#ifdef TREEDEBUG + xi_tree_check_fence( ); + validate_node( p ); +#endif + xi_tree_free_internal( VOIDPTR_TO_TREEPTR( p ), TRUE ); +} + +void * +xi_tree_get_parent( void *p ) +{ + TREE_NODE *parent; + +#ifdef TREEDEBUG + validate_node( p ); +#endif + parent = VOIDPTR_TO_TREEPTR( p )->parent; + return ( ( parent == top ) ? NULL : TREEPTR_TO_VOIDPTR( parent ) ); +} + +void * +xi_tree_malloc_body( size_t size, void *parent +#ifdef TREEDEBUG + ,int line, char *file +#endif +) +{ + TREE_NODE *tn; + +#ifdef TREEDEBUG + size_t orig_size = size; + + xi_tree_check_fence( ); + validate_node( parent ); + adjust_size( &size ); +#endif + tn = ( TREE_NODE * ) heap_malloc( size + SIZEOF_TREE_NODE ); + if ( !tn ) + { + ( *error_fcn ) ( ); + return NULL; + } +#ifdef TREEDEBUG + memset( ( char * ) tn + SIZEOF_TREE_NODE + orig_size, + PADCHAR, ( long ) ( size - orig_size ) ); + tn->file = ( char * ) heap_malloc( strlen( file ) + 1 ); + if ( !tn->file ) + { + ( *error_fcn ) ( ); + return NULL; + } + strcpy( tn->file, file ); + tn->line = line; + tn->magic = MAGIC; + tn->size = size; + node_count++; +#endif + tn->child = NULL; + tn->sibling = tn; + if ( parent == NULL ) + parent = TREEPTR_TO_VOIDPTR( top ); + tn->parent = VOIDPTR_TO_TREEPTR( parent ); + if ( tn->parent->child == NULL ) + tn->parent->child = tn; + else + { + /* insert tn in the sibling list */ + tn->sibling = tn->parent->child->sibling; + tn->parent->child->sibling = tn; + } + return ( TREEPTR_TO_VOIDPTR( tn ) ); +} + +void * +xi_tree_realloc_body( void *p, size_t size +#ifdef TREEDEBUG + ,int line, char *file +#endif +) +{ + TREE_NODE *old_t; + TREE_NODE *new_t; + TREE_NODE *tp; + +#ifdef TREEDEBUG + size_t orig_size = size; + + xi_tree_check_fence( ); + adjust_size( &size ); +#endif + old_t = VOIDPTR_TO_TREEPTR( p ); +#ifdef TREEDEBUG + validate_node( p ); +#endif + new_t = ( TREE_NODE * ) heap_realloc( old_t, ( size + SIZEOF_TREE_NODE ) ); +#ifdef TREEDEBUG + if ( !new_t ) + { + ( *error_fcn ) ( ); + return NULL; + } + memset( ( char * ) new_t + SIZEOF_TREE_NODE + orig_size, + PADCHAR, ( long ) ( size - orig_size ) ); + new_t->line = line; + new_t->size = size; + heap_free( new_t->file ); + new_t->file = ( char * ) heap_malloc( strlen( file ) + 1 ); + if ( !new_t->file ) + { + ( *error_fcn ) ( ); + return NULL; + } + strcpy( new_t->file, file ); +#endif + + if ( new_t != old_t ) + { + /* change parent pointer */ + if ( new_t->parent->child == old_t ) + new_t->parent->child = new_t; + + /* change sibling pointers */ + for ( tp = new_t; tp->sibling != old_t; tp = tp->sibling ) + ; + tp->sibling = new_t; + + /* change children pointers */ + tp = new_t->child; + if ( tp != NULL ) + do + { + tp->parent = new_t; + tp = tp->sibling; + } while ( tp != new_t->child ); + } + return ( TREEPTR_TO_VOIDPTR( new_t ) ) + ; +} + +static void +xi_tree_dbg_internal( TREE_NODE * tn, int level ) +{ + char buf[150]; + char *s; + TREE_NODE *tn2; + int i, + l; + + if ( tn == NULL ) + return; + /* print tab indent indicating level */ + s = buf; + for ( l = level; l; l-- ) + { + for ( i = 0; i < DBGTAB; i++ ) + *s++ = ' '; + } +#ifdef TREEDEBUG + sprintf( s, "node %08lx: par=%08lx, sib=%08lx, ch=%08lx, file=%s, line=%d", + ( long ) ( tn ), ( long ) ( tn->parent ), ( long ) ( tn->sibling ), + ( long ) ( tn->child ), tn->file, tn->line ); +#else + sprintf( s, "node %08lx: par=%08lx, sib=%08lx, ch=%08lx", + ( long ) tn, ( long ) ( tn->parent ), ( long ) ( tn->sibling ), + ( long ) ( tn->child ) ); +#endif + xi_dbg( buf ); + tn2 = tn->child; + if ( tn2 != NULL ) + do + { + xi_tree_dbg_internal( tn2, level + 1 ); + tn2 = tn2->sibling; + } while ( tn2 != tn->child ); +} + +void +xi_tree_dbg( char *title ) +{ + char buf[100]; + + sprintf( buf, "TREE MEMORY DEBUG TRACE (%s)", title ); + xi_dbg( buf ); + xi_dbg( "=======================" ); + xi_tree_dbg_internal( top, 0 ); + heap_dbg( title ); + xi_tree_check_sanity( title ); +} + +static void +xi_tree_check_sanity_internal( TREE_NODE * tn, char *title, + int *count ) +{ + TREE_NODE *tn2; + +#ifdef TREEDEBUG +#ifdef PAD + int i; + + /* check pad bytes for node */ + if ( tn != &topnode ) + for ( i = tn->size - PAD; i < tn->size; i++ ) + if ( *( ( char * ) tn + SIZEOF_TREE_NODE + i ) != PADCHAR ) + XinDialogFatal( "xi_tree_node padding corrupted: node=%08lx, file=%s, line=%d", + ( long ) ( tn ), tn->file, tn->line ); +#endif +#endif + /* check that all children point to this node */ + tn2 = tn->child; + ( *count )++; + if ( tn2 != NULL ) + do + { + if ( tn2->parent != tn ) + XinDialogFatal( "memory check %s: tree node %08lx has bad parent", + title, ( long ) ( tn2 ) ); + xi_tree_check_sanity_internal( tn2, title, count ); + tn2 = tn2->sibling; + } while ( tn2 != tn->child ); +} + +void +xi_tree_check_sanity( char *title ) +{ + int count = 0; + + xi_tree_check_sanity_internal( top, title, &count ); +#ifdef TREEDEBUG + if ( count != node_count ) + XinDialogFatal( "tree sanity check failed: tree count=%d, allocation count=%d", + count, node_count ); +#endif +} + +#ifdef TREEDEBUG +void *xi_tree_malloc_stub( size_t size, void *parent ); +void * +xi_tree_malloc_stub( size_t size, void *parent ) +{ + return ( xi_tree_malloc_body( size, parent, 0, "(unknown)" ) ); +} + +void *xi_tree_realloc_stub( void *p, size_t size ); +void * +xi_tree_realloc_stub( void *p, size_t size ) +{ + return ( xi_tree_realloc_body( p, size, 0, "(unknown)" ) ); +} + +#else +void * +xi_tree_malloc_stub( size_t size, void *parent, + int line, char *file ); +void * +xi_tree_malloc_stub( size_t size, void *parent, + int line, char *file ) +{ + NOREF( line ); + NOREF( file ); + return ( xi_tree_malloc_body( size, parent ) ); +} + +void * +xi_tree_realloc_stub( void *p, size_t size, + int line, char *file ); +void * +xi_tree_realloc_stub( void *p, size_t size, + int line, char *file ) +{ + NOREF( line ); + NOREF( file ); + return ( xi_tree_realloc_body( p, size ) ); +} + +#endif + +void +xi_tree_reg_error_fcn( void ( *fcn ) ( void ) ) +{ + error_fcn = fcn; +} diff --git a/src/xi01/xiutils.c b/src/xi01/xiutils.c new file mode 100644 index 000000000..fffafd30a --- /dev/null +++ b/src/xi01/xiutils.c @@ -0,0 +1,4160 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#define XI_INTERNAL +#define XI_R3_COMPAT +#include "xi.h" +#include "xiutils.h" +#include "xitext.h" +#include "xistx.h" +#include "xilm.h" +#include "xilmst.h" +#include "xiport.h" + + +#if XIWS == XIWS_WM +#define STX_VERT_FUDGE 0 +//Gia' definito altrove! #define BORDER_WIDTH 8 +#define EDIT_BORDER_WIDTH_Y 0 +#define EDIT_BORDER_SPACE_Y 0 +#define BORDER_WIDTH_X 8 +#define BORDER_WIDTH_Y 0 +#define BORDER_SPACE_X 0 +#define BORDER_SPACE_Y 0 +#else +#define STX_VERT_FUDGE 6 +//Gia' definito altrove! #define BORDER_WIDTH 2 +#define EDIT_BORDER_WIDTH_Y 1 +#define EDIT_BORDER_SPACE_Y 1 +#define BORDER_WIDTH_X 1 +#define BORDER_WIDTH_Y 1 +#define BORDER_SPACE_X 1 +#define BORDER_SPACE_Y 1 +#endif + +XinFont *xi_sysfont = NULL; +static XI_OBJ *xi_drag_list_obj = NULL; + +#define MAX_RADIO_BUTTONS 30 + +XinBrush ltgray_cbrush = {XinBrushSolid, XI_COLOR_LTGRAY}; +XinBrush gray_cbrush = {XinBrushSolid, XI_COLOR_GRAY}; +XinBrush hollow_cbrush = {XinBrushHollow, XI_COLOR_WHITE}; +XinPen hollow_cpen = {0, XinPenHollow, XI_COLOR_WHITE}; +XinPen black_cpen = {1, XinPenSolid, XI_COLOR_BLACK}; +XinPen rubber_cpen = {1, XinPenDashed, XI_COLOR_BLACK}; +XinBrush white_cbrush = {XinBrushSolid, XI_COLOR_WHITE}; + +static XinWindow cur_window; + +static XI_OBJ *cur_itf; +static int cur_delta_x; +static int cur_delta_y; + +static BOOLEAN font_set = FALSE; +static BOOLEAN update_pending = FALSE; + +static int xi_sysvals[XI_NBR_SYSVALS]; +static long xi_preferences[XI_NBR_PREFERENCES] = +{ + 1, /* XI_PREF_OVERLAP */ + '\t', /* XI_PREF_FORM_TAB_CHAR */ + XI_KEY_BTAB, /* XI_PREF_FORM_BACKTAB_CHAR */ + 1, /* XI_PREF_SCROLL_INC */ + TRUE, /* XI_PREF_3D_LOOK */ + FALSE, /* XI_PREF_USE_APP_DATA */ + FALSE, /* XI_PREF_AUTOSEL_ON_MOUSE */ + 1, /* XI_PREF_CELL_BTN_ICON_X */ + 1, /* XI_PREF_CELL_BTN_ICON_Y */ + FALSE, /* XI_PREF_R4_API */ + '#', /* XI_PREF_PASSWORD_CHAR */ + FALSE, /* XI_PREF_USE_TX_SUPPORT */ + FALSE, /* XI_PREF_SINGLE_CLICK_COL_SELECT */ +#if XIWS == XIWS_WM + 0, /* XI_PREF_COLUMN_OFFSET */ + 0, /* XI_PREF_SB_OFFSET */ + 8, /* XI_PREF_SB_WIDTH */ + 8, /* XI_PREF_SB_HEIGHT */ + 0, /* XI_PREF_SIZE_CURSOR_RID */ + 0, /* XI_PREF_HAND_CURSOR_RID */ + 0, /* XI_PREF_VSIZE_CURSOR_RID */ + 0, /* XI_PREF_COMBO_ICON */ + XI_COLOR_WHITE, /* XI_PREF_COLOR_LIGHT */ + XI_COLOR_LTGRAY, /* XI_PREF_COLOR_CTRL */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DARK */ + FALSE, /* XI_PREF_OPTIMIZE_CELL_REQUESTS */ + 1, /* XI_PREF_CARET_WIDTH */ + 500, /* XI_PREF_TRIPLE_CLICK_TIME */ + K_F2, /* XI_PREF_BUTTON_KEY */ + TRUE, /* XI_PREF_LIMIT_MIN_WIN_SIZE */ + 5, /* XI_PREF_DEFAULT_MAX_LINES_IN_CELL */ + FALSE, /* XI_PREF_KEEP_FOCUS_FIXED */ + TRUE, /* XI_PREF_NATIVE_CTRLS */ + XI_KEY_F3, /* XI_PREF_ITF_TAB_CHAR */ + XI_KEY_F4, /* XI_PREF_ITF_BACKTAB_CHAR */ + 16, /* XI_PREF_ITF_WS_RIGHT */ + 4, /* XI_PREF_ITF_WS_BOTTOM */ + 40, /* XI_PREF_VIR_SP_H */ + 20, /* XI_PREF_VIR_SP_V */ + TRUE, /* XI_PREF_DBL_PRESSES_BUTTON */ + 1, /* XI_PREF_CONTAINER_GRID_WIDTH */ + TRUE, /* XI_PREF_MULTILINE_QUICK_PASTE */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DISABLED */ + 24, /* XI_PREF_BUTTON_HEIGHT */ + 32, /* XI_PREF_BUTTON_PAD */ + 16, /* XI_PREF_HORZ_SPACING */ + 0, /* XI_PREF_VERT_SPACING */ + 0, /* XI_PREF_HORZ_PIXEL_SPACING */ + 0, /* XI_PREF_VERT_PIXEL_SPACING */ + 16, /* XI_PREF_ITF_MIN_TOP */ + 8, /* XI_PREF_ITF_MIN_LEFT */ + FALSE, /* XI_PREF_XIL */ + FALSE, /* XI_PREF_ASSERT_ON_NULL_CID */ + FALSE, /* XI_PREF_NO_BUTTON_SPACE */ + +#elif XIWS == XIWS_PM + 2, /* XI_PREF_COLUMN_OFFSET */ + 0, /* XI_PREF_SB_OFFSET */ + 16, /* XI_PREF_SB_WIDTH */ + 16, /* XI_PREF_SB_HEIGHT */ + XI_CURSOR_RESIZE, /* XI_PREF_SIZE_CURSOR_RID */ + XI_CURSOR_HAND, /* XI_PREF_HAND_CURSOR_RID */ + XI_CURSOR_VRESIZE, /* XI_PREF_VSIZE_CURSOR_RID */ + COMBO_ICON, /* XI_PREF_COMBO_ICON */ + XI_COLOR_WHITE, /* XI_PREF_COLOR_LIGHT */ + XI_COLOR_LTGRAY, /* XI_PREF_COLOR_CTRL */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DARK */ + TRUE, /* XI_PREF_OPTIMIZE_CELL_REQUESTS */ + 1, /* XI_PREF_CARET_WIDTH */ + 500, /* XI_PREF_TRIPLE_CLICK_TIME */ + 0, /* XI_PREF_BUTTON_KEY */ + TRUE, /* XI_PREF_LIMIT_MIN_WIN_SIZE */ + 5, /* XI_PREF_DEFAULT_MAX_LINES_IN_CELL */ + FALSE, /* XI_PREF_KEEP_FOCUS_FIXED */ + TRUE, /* XI_PREF_NATIVE_CTRLS */ + XI_KEY_F3, /* XI_PREF_ITF_TAB_CHAR */ + XI_KEY_F4, /* XI_PREF_ITF_BACKTAB_CHAR */ + 16, /* XI_PREF_ITF_WS_RIGHT */ + 4, /* XI_PREF_ITF_WS_BOTTOM */ + 40, /* XI_PREF_VIR_SP_H */ + 20, /* XI_PREF_VIR_SP_V */ + TRUE, /* XI_PREF_DBL_PRESSES_BUTTON */ + 1, /* XI_PREF_CONTAINER_GRID_WIDTH */ + TRUE, /* XI_PREF_MULTILINE_QUICK_PASTE */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DISABLED */ + 12, /* XI_PREF_BUTTON_HEIGHT */ + 32, /* XI_PREF_BUTTON_PAD */ + 16, /* XI_PREF_HORZ_SPACING */ + 2, /* XI_PREF_VERT_SPACING */ + 0, /* XI_PREF_HORZ_PIXEL_SPACING */ + 0, /* XI_PREF_VERT_PIXEL_SPACING */ + 24, /* XI_PREF_ITF_MIN_TOP */ + 8, /* XI_PREF_ITF_MIN_LEFT */ + FALSE, /* XI_PREF_XIL */ + FALSE, /* XI_PREF_ASSERT_ON_NULL_CID */ + FALSE, /* XI_PREF_NO_BUTTON_SPACE */ + +#elif XIWS == XIWS_MAC + 2, /* XI_PREF_COLUMN_OFFSET */ + 0, /* XI_PREF_SB_OFFSET */ + 16, /* XI_PREF_SB_WIDTH */ + 16, /* XI_PREF_SB_HEIGHT */ + XI_CURSOR_RESIZE, /* XI_PREF_SIZE_CURSOR_RID */ + XI_CURSOR_HAND, /* XI_PREF_HAND_CURSOR_RID */ + XI_CURSOR_VRESIZE, /* XI_PREF_VSIZE_CURSOR_RID */ + COMBO_ICON, /* XI_PREF_COMBO_ICON */ + XI_COLOR_WHITE, /* XI_PREF_COLOR_LIGHT */ + XI_COLOR_LTGRAY, /* XI_PREF_COLOR_CTRL */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DARK */ + TRUE, /* XI_PREF_OPTIMIZE_CELL_REQUESTS */ + 1, /* XI_PREF_CARET_WIDTH */ + 500, /* XI_PREF_TRIPLE_CLICK_TIME */ + 0, /* XI_PREF_BUTTON_KEY */ + TRUE, /* XI_PREF_LIMIT_MIN_WIN_SIZE */ + 5, /* XI_PREF_DEFAULT_MAX_LINES_IN_CELL */ + FALSE, /* XI_PREF_KEEP_FOCUS_FIXED */ + TRUE, /* XI_PREF_NATIVE_CTRLS */ + XI_KEY_F3, /* XI_PREF_ITF_TAB_CHAR */ + XI_KEY_F4, /* XI_PREF_ITF_BACKTAB_CHAR */ + 16, /* XI_PREF_ITF_WS_RIGHT */ + 4, /* XI_PREF_ITF_WS_BOTTOM */ + 40, /* XI_PREF_VIR_SP_H */ + 20, /* XI_PREF_VIR_SP_V */ + TRUE, /* XI_PREF_DBL_PRESSES_BUTTON */ + 1, /* XI_PREF_CONTAINER_GRID_WIDTH */ + TRUE, /* XI_PREF_MULTILINE_QUICK_PASTE */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DISABLED */ + 12, /* XI_PREF_BUTTON_HEIGHT */ + 32, /* XI_PREF_BUTTON_PAD */ + 16, /* XI_PREF_HORZ_SPACING */ + 2, /* XI_PREF_VERT_SPACING */ + 0, /* XI_PREF_HORZ_PIXEL_SPACING */ + 0, /* XI_PREF_VERT_PIXEL_SPACING */ + 40, /* XI_PREF_ITF_MIN_TOP */ + 8, /* XI_PREF_ITF_MIN_LEFT */ + FALSE, /* XI_PREF_XIL */ + FALSE, /* XI_PREF_ASSERT_ON_NULL_CID */ + FALSE /* XI_PREF_NO_BUTTON_SPACE */ + /* Some compiler on the Mac won't accept a comma on the last entry, so don't + * put one. This means you have to put a comma after the old last entry when + * you add a new one. */ + +#elif XIWS == XIWS_XM || XIWS == XIWS_WXGTK + 2, /* XI_PREF_COLUMN_OFFSET */ + 0, /* XI_PREF_SB_OFFSET */ + 16, /* XI_PREF_SB_WIDTH */ + 16, /* XI_PREF_SB_HEIGHT */ + XI_CURSOR_RESIZE, /* XI_PREF_SIZE_CURSOR_RID */ + XI_CURSOR_HAND, /* XI_PREF_HAND_CURSOR_RID */ + XI_CURSOR_VRESIZE, /* XI_PREF_VSIZE_CURSOR_RID */ + COMBO_ICON, /* XI_PREF_COMBO_ICON */ + XI_COLOR_WHITE, /* XI_PREF_COLOR_LIGHT */ + XI_COLOR_LTGRAY, /* XI_PREF_COLOR_CTRL */ + XI_COLOR_DKGRAY, /* XI_PREF_COLOR_DARK */ + TRUE, /* XI_PREF_OPTIMIZE_CELL_REQUESTS */ + 1, /* XI_PREF_CARET_WIDTH */ + 500, /* XI_PREF_TRIPLE_CLICK_TIME */ + 0, /* XI_PREF_BUTTON_KEY */ + TRUE, /* XI_PREF_LIMIT_MIN_WIN_SIZE */ + 5, /* XI_PREF_DEFAULT_MAX_LINES_IN_CELL */ + FALSE, /* XI_PREF_KEEP_FOCUS_FIXED */ + TRUE, /* XI_PREF_NATIVE_CTRLS */ + XI_KEY_F3, /* XI_PREF_ITF_TAB_CHAR */ + XI_KEY_F4, /* XI_PREF_ITF_BACKTAB_CHAR */ + 16, /* XI_PREF_ITF_WS_RIGHT */ + 4, /* XI_PREF_ITF_WS_BOTTOM */ + 40, /* XI_PREF_VIR_SP_H */ + 20, /* XI_PREF_VIR_SP_V */ + TRUE, /* XI_PREF_DBL_PRESSES_BUTTON */ + 1, /* XI_PREF_CONTAINER_GRID_WIDTH */ + TRUE, /* XI_PREF_MULTILINE_QUICK_PASTE */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DISABLED */ + 12, /* XI_PREF_BUTTON_HEIGHT */ + 32, /* XI_PREF_BUTTON_PAD */ + 16, /* XI_PREF_HORZ_SPACING */ + 2, /* XI_PREF_VERT_SPACING */ + 0, /* XI_PREF_HORZ_PIXEL_SPACING */ + 0, /* XI_PREF_VERT_PIXEL_SPACING */ + 0, /* XI_PREF_ITF_MIN_TOP */ + 8, /* XI_PREF_ITF_MIN_LEFT */ + FALSE, /* XI_PREF_XIL */ + FALSE, /* XI_PREF_ASSERT_ON_NULL_CID */ + FALSE, /* XI_PREF_NO_BUTTON_SPACE */ + +#elif XIWS == XIWS_WIN + 2, /* XI_PREF_COLUMN_OFFSET */ + 0, /* XI_PREF_SB_OFFSET */ + 16, /* XI_PREF_SB_WIDTH */ + 16, /* XI_PREF_SB_HEIGHT */ + XI_CURSOR_RESIZE, /* XI_PREF_SIZE_CURSOR_RID */ + XI_CURSOR_HAND, /* XI_PREF_HAND_CURSOR_RID */ + XI_CURSOR_VRESIZE, /* XI_PREF_VSIZE_CURSOR_RID */ + COMBO_ICON, /* XI_PREF_COMBO_ICON */ + XI_COLOR_WHITE, /* XI_PREF_COLOR_LIGHT */ + XI_COLOR_LTGRAY, /* XI_PREF_COLOR_CTRL */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DARK */ + TRUE, /* XI_PREF_OPTIMIZE_CELL_REQUESTS */ + 1, /* XI_PREF_CARET_WIDTH */ + 500, /* XI_PREF_TRIPLE_CLICK_TIME */ + XI_KEY_DOWN | XI_MOD_ALT, /* XI_PREF_BUTTON_KEY */ + TRUE, /* XI_PREF_LIMIT_MIN_WIN_SIZE */ + 5, /* XI_PREF_DEFAULT_MAX_LINES_IN_CELL */ + FALSE, /* XI_PREF_KEEP_FOCUS_FIXED */ + TRUE, /* XI_PREF_NATIVE_CTRLS */ + XI_KEY_F3, /* XI_PREF_ITF_TAB_CHAR */ + XI_KEY_F4, /* XI_PREF_ITF_BACKTAB_CHAR */ + 16, /* XI_PREF_ITF_WS_RIGHT */ + 4, /* XI_PREF_ITF_WS_BOTTOM */ + 40, /* XI_PREF_VIR_SP_H */ + 20, /* XI_PREF_VIR_SP_V */ + TRUE, /* XI_PREF_DBL_PRESSES_BUTTON */ + 1, /* XI_PREF_CONTAINER_GRID_WIDTH */ + TRUE, /* XI_PREF_MULTILINE_QUICK_PASTE */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DISABLED */ + 12, /* XI_PREF_BUTTON_HEIGHT */ + 32, /* XI_PREF_BUTTON_PAD */ + 16, /* XI_PREF_HORZ_SPACING */ + 2, /* XI_PREF_VERT_SPACING */ + 0, /* XI_PREF_HORZ_PIXEL_SPACING */ + 0, /* XI_PREF_VERT_PIXEL_SPACING */ + 30, /* XI_PREF_ITF_MIN_TOP */ + 8, /* XI_PREF_ITF_MIN_LEFT */ + FALSE, /* XI_PREF_XIL */ + FALSE, /* XI_PREF_ASSERT_ON_NULL_CID */ + FALSE, /* XI_PREF_NO_BUTTON_SPACE */ + +#else + 2, /* XI_PREF_COLUMN_OFFSET */ + 0, /* XI_PREF_SB_OFFSET */ + 16, /* XI_PREF_SB_WIDTH */ + 16, /* XI_PREF_SB_HEIGHT */ + 0, /* XI_PREF_SIZE_CURSOR_RID */ + 0, /* XI_PREF_HAND_CURSOR_RID */ + 0, /* XI_PREF_VSIZE_CURSOR_RID */ + 0, /* XI_PREF_COMBO_ICON */ + XI_COLOR_WHITE, /* XI_PREF_COLOR_LIGHT */ + XI_COLOR_LTGRAY, /* XI_PREF_COLOR_CTRL */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DARK */ + TRUE, /* XI_PREF_OPTIMIZE_CELL_REQUESTS */ + 1, /* XI_PREF_CARET_WIDTH */ + 500, /* XI_PREF_TRIPLE_CLICK_TIME */ + 0, /* XI_PREF_BUTTON_KEY */ + TRUE, /* XI_PREF_LIMIT_MIN_WIN_SIZE */ + 5, /* XI_PREF_DEFAULT_MAX_LINES_IN_CELL */ + FALSE, /* XI_PREF_KEEP_FOCUS_FIXED */ + TRUE, /* XI_PREF_NATIVE_CTRLS */ + XI_KEY_F3, /* XI_PREF_ITF_TAB_CHAR */ + XI_KEY_F4, /* XI_PREF_ITF_BACKTAB_CHAR */ + 16, /* XI_PREF_ITF_WS_RIGHT */ + 4, /* XI_PREF_ITF_WS_BOTTOM */ + 40, /* XI_PREF_VIR_SP_H */ + 20, /* XI_PREF_VIR_SP_V */ + TRUE, /* XI_PREF_DBL_PRESSES_BUTTON */ + 1, /* XI_PREF_CONTAINER_GRID_WIDTH */ + TRUE, /* XI_PREF_MULTILINE_QUICK_PASTE */ + XI_COLOR_GRAY, /* XI_PREF_COLOR_DISABLED */ + 12, /* XI_PREF_BUTTON_HEIGHT */ + 32, /* XI_PREF_BUTTON_PAD */ + 16, /* XI_PREF_HORZ_SPACING */ + 2, /* XI_PREF_VERT_SPACING */ + 0, /* XI_PREF_HORZ_PIXEL_SPACING */ + 0, /* XI_PREF_VERT_PIXEL_SPACING */ + 0, /* XI_PREF_ITF_MIN_TOP */ + 8, /* XI_PREF_ITF_MIN_LEFT */ + FALSE, /* XI_PREF_XIL */ + FALSE, /* XI_PREF_ASSERT_ON_NULL_CID */ + FALSE, /* XI_PREF_NO_BUTTON_SPACE */ + +#endif + +}; +static long aga_preferences[AGA_NBR_PREFERENCES] = { XI_COLOR_LTGRAY, XI_COLOR_GRAY, XI_COLOR_DKGRAY, XI_COLOR_BLACK }; + + +XinRect big_clip = { +0, 0, 10000, 10000}; + +typedef struct +{ + XinFont *font; + int leading; + int ascent; + int descent; + int char_width; +} FONT_INFO; + +static FONT_INFO* font_info = NULL; +static int font_info_cnt = 0; + +static void xi_caret_suspend( XinWindow win ); +static void xi_caret_restore( XinWindow win ); +static void recalc_metrics( XI_OBJ * xi_obj ); + +char* gstrncpy( char *dst, const char *src, int n ) +{ + char *p = dst; + + while ( n > 0 && *src != 0 ) + { + *p++ = *src++; + n--; + } + if ( n != 0 ) + *p++ = '\0'; + return ( dst ); +} + +char* tstrncpy( char *dst, const char *src, int n ) +{ + gstrncpy(dst, src, n); + dst[n - 1] = '\0'; + return ( dst ); +} + +void order_ints( int *ip1, int *ip2 ) +{ + if ( *ip1 > *ip2 ) + { + const int temp = *ip1; + *ip1 = *ip2; + *ip2 = temp; + } +} + +XinRect * +xi_inflate_rect( XinRect * rct, int amount ) +{ + rct->bottom += amount; + rct->right += amount; + rct->left -= amount; + rct->top -= amount; + return ( rct ); +} + +void +xi_offset_rect( XinRect * rct, int delta_x, int delta_y ) +{ + rct->top += delta_y; + rct->bottom += delta_y; + rct->right += delta_x; + rct->left += delta_x; +} + +int +clip( int val, int mn, int mx ) +{ + return ( val < mn ? mn : ( val > mx ? mx : val ) ); +} + +void +xi_realloc_array( void **ptr, int nbr, size_t sz, void *parent ) +{ + BOOLEAN is_zero = ( nbr * sz ) == 0; + + if ( !*ptr ) + { + if ( is_zero ) + *ptr = NULL; + else + *ptr = ( void * ) xi_tree_malloc( nbr * sz, parent ); + } + else + { + if ( is_zero ) + { + xi_tree_free( *ptr ); + *ptr = NULL; + } + else + *ptr = ( void * ) xi_tree_realloc( *ptr, nbr * sz ); + } +} + +static void +do_vir_pan_event( XI_OBJ * itf, int h, int v, BOOLEAN before ) +{ + XI_EVENT xiev; + + MEMCLEAR( xiev ); + xiev.type = XIE_VIR_PAN; + xiev.v.vir_pan.before_pan = before; + xiev.v.vir_pan.delta_x = h; + xiev.v.vir_pan.delta_y = v; + ( *( XI_EH_TYPE ) itf->v.itf->xi_eh ) ( itf, &xiev ); +} + +static void +set_sb_positions( XI_OBJ * itf ) +{ + XI_ITF_DATA *itf_data; + XinWindow win; + int ps; + + itf_data = itf->v.itf; + win = xi_get_window( itf ); + if ( itf_data->max_xi_pnt.v - itf_data->win_xi_pnt.v ) + ps = ( int ) ( 100L * ( long ) ( itf_data->phys_xi_pnt.v ) / + ( ( long ) itf_data->max_xi_pnt.v - + ( long ) itf_data->win_xi_pnt.v ) ); + else + ps = 0; + XinScrollBarPositionSet( win, XinScrollBarTypeVertical, ps ); + if ( itf_data->max_xi_pnt.h - itf_data->win_xi_pnt.h ) + ps = ( int ) ( 100L * ( long ) ( itf_data->phys_xi_pnt.h ) / + ( ( long ) itf_data->max_xi_pnt.h - + ( long ) itf_data->win_xi_pnt.h ) ); + else + ps = 0; + XinScrollBarPositionSet( win, XinScrollBarTypeHorizontal, ps ); +} + +void +xi_get_hsb_rect( XI_OBJ * xi_obj, XinRect * rctp ) +{ + XI_LIST_DATA *list_data; + LM_DATA *lmp; + XinRect rct1, + rct3; + XI_OBJ **members; + int nbr_members; + +#if XIWS == XIWS_WIN + XinRect r; + +#endif + + list_data = xi_obj->v.list; + lmp = ( LM_DATA * ) list_data->lm; + if ( list_data->have_hsb_rct ) + { + *rctp = list_data->hsb_rct; + return; + } +#if XIWS == XIWS_WIN + if ( list_data->hsb_win ) + XinWindowRectGet( list_data->hsb_win, &r ); +#endif + members = xi_get_member_list( xi_obj, &nbr_members ); + if ( !lmp->nbr_columns ) + { + rct3.left = lmp->rct.left; + rct1 = lmp->rct; + } + else + { + if ( lmp->fixed_columns ) + { + xi_get_rect( members[lmp->fixed_columns - 1], &rct1 ); + rct3.left = rct1.right; + } + else + { + xi_get_rect( members[0], &rct1 ); + rct3.left = lmp->rct.left; + } + } + /* subtract one so that the top of the horizontal scroll bar overlaps the + * bottom of the list by one pixel. */ +#if XIWS != XIWS_WM + rct3.top = rct1.bottom - 1; + rct3.right = lmp->rct.left + lmp->pixel_width + 2 * BORDER_WIDTH; +#else + rct3.top = rct1.bottom; + rct3.right = lmp->rct.left + lmp->pixel_width; +#endif + rct3.bottom = rct3.top + ( int ) xi_get_pref( XI_PREF_SB_HEIGHT ); +#if XIWS == XIWS_WIN + if ( list_data->hsb_win ) + rct3.bottom = rct3.top + r.bottom; +#endif + if ( rct3.left >= rct3.right ) + rct3.right = rct3.left + 1; + *rctp = rct3; + list_data->hsb_rct = rct3; + list_data->have_hsb_rct = TRUE; +} + +void +xi_get_sb_rect( XI_OBJ * xi_obj, XinRect * rctp ) +{ + XinRect rct; + int offset, + width; + XI_LIST_DATA *list_data; + LM_DATA *lmp; + +#if XIWS == XIWS_WIN + XinRect r; + +#endif + + list_data = xi_obj->v.list; + lmp = ( LM_DATA * ) list_data->lm; + if ( list_data->have_sb_rct ) + { + *rctp = list_data->sb_rct; + return; + } +#if XIWS == XIWS_WIN + if ( list_data->sb_win ) + XinWindowRectGet( list_data->sb_win, &r ); +#endif + lm_get_rect( list_data->lm, LM_LIST, 0, &rct ); + list_data->sb_offset = offset = ( int ) xi_get_pref( XI_PREF_SB_OFFSET ); + list_data->sb_width = width = ( int ) xi_get_pref( XI_PREF_SB_WIDTH ); + + /* subtract one from the left of the scroll bar rectangle, so that the left + * edge of the scroll bar overlaps the right double wide line, by one pixel. */ +#if XIWS != XIWS_WM + if ( list_data->width ) + rct.left = rct.left + lmp->pixel_width + offset + 2 * BORDER_WIDTH - 1; + else + rct.left = rct.right + offset - 1; +#else + if ( list_data->width ) + rct.left = rct.left + lmp->pixel_width + offset; + else + rct.left = rct.right + offset; +#endif + rct.right = rct.left + width; +#if XIWS == XIWS_WIN + if ( list_data->sb_win ) + rct.right = rct.left + r.right; +#endif + if ( list_data->scroll_bar_button ) + { + LM_DATA *lm_data; + + lm_data = ( LM_DATA * ) list_data->lm; + list_data->sbb_rct.top = rct.top + 1; /* Add one, so that there is + * room for the double line + * border */ + list_data->sbb_rct.bottom = lm_data->pix_row1_top - BORDER_WIDTH + 1; + list_data->sbb_rct.left = rct.left; + list_data->sbb_rct.right = rct.right; +#if XIWS == XIWS_WIN + if ( list_data->sb_win ) + list_data->sbb_rct.right = list_data->sbb_rct.left + r.right; +#endif +#if XIWS == XIWS_WM + rct.top = lm_data->pix_row1_top; +#else + rct.top = list_data->sbb_rct.bottom; +#endif + } + *rctp = rct; + list_data->sb_rct = rct; + list_data->have_sb_rct = TRUE; +} + +void +xi_move_list_scroll_bar( XI_OBJ * xi_obj ) +{ + XinRect rct; + XinWindow win = xi_obj->itf->v.itf->xin_win; + XinWindow sb_win; + XI_LIST_DATA *list_data; + XI_ITF_DATA *itf_data; + + list_data = xi_obj->v.list; + if ( list_data->scroll_bar_button ) + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, + &list_data->sbb_rct ); + xi_get_sb_rect( xi_obj, &rct ); + + itf_data = xi_obj->itf->v.itf; + xi_offset_rect( &rct, -itf_data->delta_x, -itf_data->delta_y ); + + sb_win = list_data->sb_win; + if ( sb_win && rct.left < rct.right && rct.top < rct.bottom ) + XinWindowRectSet( sb_win, &rct ); + if ( list_data->scroll_bar_button ) + xi_invalidate_rect( win, &list_data->sbb_rct ); +} + +void +xi_move_list_hscroll_bar( XI_OBJ * xi_obj ) +{ + XinRect rct; + XinWindow hsb_win; + XI_LIST_DATA *list_data; + XI_ITF_DATA *itf_data; + + list_data = xi_obj->v.list; + xi_get_hsb_rect( xi_obj, &rct ); + + itf_data = xi_obj->itf->v.itf; + xi_offset_rect( &rct, -itf_data->delta_x, -itf_data->delta_y ); + hsb_win = list_data->hsb_win; + if (hsb_win && rct.left < rct.right && rct.top < rct.bottom) + XinWindowRectSet( hsb_win, &rct ); +} + +BOOLEAN +xi_half_baked( XinWindow win ) +{ + XI_OBJ *itf; + + itf = xi_get_itf( win ); + if ( itf ) + return itf->v.itf->half_baked; + return FALSE; +} + +XinFont * +xi_get_system_font( void ) +{ + return xi_sysfont; +} + +XI_OBJ * +xi_get_drag_list_obj( void ) +{ + return xi_drag_list_obj; +} + +int +xi_get_sysval( XI_SV_TYPE valtype ) +{ + return ( xi_sysvals[valtype] ); +} + +void +xi_set_sysval( XI_SV_TYPE valtype, int value ) +{ + xi_sysvals[valtype] = value; +} + +void +xi_clean_up( ) +{ + FONT_INFO* fi; + int num; +#ifndef NO_PRIMARY_SELECTION +#if XIWS == XIWS_XM + clean_primesel( ); +#endif +#endif + if ( xi_sysfont != NULL ) + XinFontDestroy( xi_sysfont ); + for ( num = 0, fi = font_info; num < font_info_cnt; num++, fi++ ) + XinFontDestroy( fi->font ); + if ( font_info != NULL ) + xi_tree_free( font_info ); + font_info = NULL; + font_info_cnt = 0; +} + +long +xi_get_pref( XI_PREF_TYPE pref_type ) +{ + return xi_preferences[pref_type]; +} + +void +xi_set_pref( XI_PREF_TYPE preftype, long value ) +{ + xi_preferences[preftype] = value; +} + +long +aga_get_pref(AGA_PREF_TYPE preftype) +{ + return aga_preferences[preftype]; +} + +void +aga_set_pref(AGA_PREF_TYPE preftype, long value) +{ + aga_preferences[preftype] = value; +} + +void +xi_set_font( XinFont * font ) +{ + font_set = TRUE; + if ( xi_sysfont != NULL ) + XinFontDestroy( xi_sysfont ); + XinFontCopy( &xi_sysfont, font ); +} + + +void +xi_set_drag_list_obj( XI_OBJ * obj ) +{ + xi_drag_list_obj = obj; +} + +void +xi_set_font_id( void *font_id ) +{ +#ifdef XI_USE_XVT + font_set = TRUE; + if ( xi_sysfont != NULL ) + XinFontDestroy( xi_sysfont ); + xi_sysfont = XinFontXvtConvert( font_id ); +#endif +} + +void +xi_init_sysvals( void ) +{ + int ascent, + descent, + leading, + height, + char_width; + + if ( !font_set ) + { + xi_sysfont = XinFontCreate( ); + XinFontFamilySet( xi_sysfont, XinFontFamilyHelvetica ); + XinFontSizeSet( xi_sysfont, 9 ); + } + xi_get_font_metrics_font( xi_sysfont, &leading, &ascent, &descent, + &char_width ); + xi_set_sysval( XI_SV_SYSFONT_ASCENT, ascent ); + xi_set_sysval( XI_SV_SYSFONT_DESCENT, descent ); + xi_set_sysval( XI_SV_SYSFONT_LEADING, leading ); + height = ascent + descent + leading; + xi_set_sysval( XI_SV_FU_HEIGHT, height + STX_VERT_FUDGE ); + xi_set_sysval( XI_SV_FU_WIDTH, char_width ); + xi_set_sysval( XI_SV_SYSFONT_HEIGHT, height ); +} + +void +xi_fu_to_pu( XI_OBJ * itf, XinPoint * pnts, int nbr_pnts ) +{ + NOREF( itf ); + + while ( nbr_pnts != 0 ) + { + pnts->v = ( short ) ( ( ( long ) pnts->v * ( long ) xi_get_fu_height( itf ) ) / ( long ) XI_FU_MULTIPLE ); + pnts->h = ( short ) ( ( ( long ) pnts->h * ( long ) xi_get_fu_width( itf ) ) / ( long ) XI_FU_MULTIPLE ); + pnts++; + nbr_pnts--; + } +} + +void +xi_pu_to_fu( XI_OBJ * itf, XinPoint * pnts, int nbr_pnts ) +{ + long fu_h, + fu_w; + + NOREF( itf ); + fu_h = ( long ) xi_get_fu_height( itf ); + fu_w = ( long ) xi_get_fu_width( itf ); + + while ( nbr_pnts != 0 ) + { + pnts->v = ( short ) ( ( ( long ) pnts->v * ( long ) XI_FU_MULTIPLE ) / fu_h ); + pnts->h = ( short ) ( ( ( long ) pnts->h * ( long ) XI_FU_MULTIPLE ) / fu_w ); + pnts++; + nbr_pnts--; + } +} + +/* +* xi_tree_realloc2() handles the degenerate case of passing in a NULL +* pointer for the old pointer. +*/ +#ifdef TREEDEBUG +char * +xi_tree_realloc_d2( char *oldp, size_t size, char *parent, int line, + char *filename ) +{ + if ( oldp == NULL ) + return ( ( char * ) xi_tree_malloc_d( size, parent, line, filename ) ); + else + return ( ( char * ) xi_tree_realloc_d( oldp, size, line, filename ) ); +} + +#else +char * +xi_tree_realloc2( char *oldp, size_t size, char *parent ) +{ + if ( oldp == NULL ) + return ( ( char * ) xi_tree_malloc( size, parent ) ); + else + return ( ( char * ) xi_tree_realloc( oldp, size ) ); +} + +#endif + +int +xi_get_text_width( XinFont * font, char *s, int len, unsigned long attrib ) +{ + char buf[4]; + int pw_size; + + if ( len == -1 ) + len = strlen( s ); + if ( attrib & XI_ATR_PASSWORD ) + { + buf[0] = ( char ) xi_get_pref( XI_PREF_PASSWORD_CHAR ); + buf[1] = '\0'; + pw_size = XinFontTextWidthGet( font, buf, 1 ); + return ( pw_size * len ); + } + else + return ( XinFontTextWidthGet( font, s, len ) ); +} + +static void +xi_draw_mnemonic_line( XinWindow win, XinFont * font, char *buf, char mnemonic, int mnemonic_instance, int horizontal, + int vertical ) +{ + char *bufp; + int left, + right; + + if ( !mnemonic ) + return; + if ( mnemonic_instance == 0 ) + mnemonic_instance = 1; + for ( bufp = buf; *bufp != '\0'; ++bufp ) + { + if ( *bufp == mnemonic ) + { + --mnemonic_instance; + if ( !mnemonic_instance ) + { + XinPen pen; + XinDrawTools dt; + XinPoint p1, + p2; + + XinWindowDrawToolsGet( win, &dt ); + left = XinFontTextWidthGet( font, buf, ( int ) ( bufp - buf ) ); + right = XinFontTextWidthGet( font, buf, ( int ) ( bufp - buf + 1 ) ); + pen = black_cpen; + pen.fore_color = dt.text_fore_color; + XinWindowPenSet( win, &pen ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + p1.h = horizontal + left; + p1.v = vertical + 1; + xi_move_to( win, p1 ); + p2.h = horizontal + right; + p2.v = p1.v; + xi_draw_line( win, p2 ); + return; + } + } + } +} + +void +xi_draw_clipped_text( XinWindow win, XinFont * font, char *s, XinRect * bound_rctp, + XinRect * clip_rctp, unsigned long attrib, BOOLEAN set_the_cpen, + int rule_and_space, int str_len, char mnemonic, short mnemonic_instance, int *bline ) +{ + int ascent, + descent, + leading, + wid; + char *buf; + int baseline; + XinRect tmp_rct; + + if ( !( attrib & XI_ATR_VISIBLE ) ) + return; + XinWindowFontMap( win, font ); + XinFontMetricsGet( font, &leading, &ascent, &descent ); + tmp_rct = *clip_rctp; + tmp_rct.bottom = tmp_rct.bottom - BORDER_WIDTH; + xi_set_clip( win, &tmp_rct ); + NOREF( set_the_cpen ); + /* TODO ????? if (set_the_cpen) XinWindowPenSet(win, &black_cpen); */ + buf = xi_get_text_string( s, attrib ); +#if XIWS == XIWS_WM + NOREF( rule_and_space ); + baseline = bound_rctp->top + 8; +#else + if ( attrib & XI_ATR_VCENTER ) + baseline = bound_rctp->top + leading + ascent + rule_and_space + + ( bound_rctp->bottom - bound_rctp->top - leading - ascent - descent ) / 2 - 1; + else + baseline = bound_rctp->top + leading + ascent + rule_and_space - 1; +#endif + if ( bline ) + *bline = baseline; + if ( attrib & XI_ATR_RJUST ) + { + wid = XinFontTextWidthGet( font, buf, -1 ); + xi_draw_text( win, font, bound_rctp->right - wid, baseline, buf, str_len ); + xi_draw_mnemonic_line( win, font, buf, mnemonic, mnemonic_instance, bound_rctp->right - wid, + baseline ); + } + else + { + if ( attrib & XI_ATR_HCENTER ) + { + int x; + + wid = XinFontTextWidthGet( font, buf, str_len ); + x = ( bound_rctp->left + bound_rctp->right ) / 2 - wid / 2; + if ( x < bound_rctp->left ) + x = bound_rctp->left; + xi_draw_text( win, font, x, baseline, buf, str_len ); + xi_draw_mnemonic_line( win, font, buf, mnemonic, mnemonic_instance, x, baseline ); + } + else + { + xi_draw_text( win, font, bound_rctp->left, baseline, buf, str_len ); + xi_draw_mnemonic_line( win, font, buf, mnemonic, mnemonic_instance, bound_rctp->left, baseline ); + } + } + xi_set_clip( win, ( XinRect * ) NULL ); +} + +void +xi_draw_text_attrib( XinWindow win, XinFont * font, int x, int y, char *s, + int len, unsigned long attrib ) +{ + char *buf; + + NOREF( len ); + if ( !( attrib & XI_ATR_VISIBLE ) ) + return; + buf = xi_get_text_string( s, attrib ); + xi_draw_text( win, font, x, y, buf, -1 ); +} + +void +xi_draw_3d_rect( XinWindow win, XinRect * rctp, BOOLEAN well, int height, + XinColor color_light, XinColor color_ctrl, XinColor color_dark ) +{ + XinRect rct; + XinPoint pnt, + pnt2; + XinPen cpen; + XinBrush cbrush; + + if ( !color_light ) + { + color_light = xi_get_pref( XI_PREF_COLOR_LIGHT ); + color_ctrl = xi_get_pref( XI_PREF_COLOR_CTRL ); + color_dark = xi_get_pref( XI_PREF_COLOR_DARK ); + } + cpen = black_cpen; + rct = *rctp; + XinWindowDrawModeSet( win, XinDrawModeCopy ); + + /* draw upper left lines */ + cpen.fore_color = well ? color_dark : color_light; + XinWindowPenSet( win, &cpen ); + pnt.h = rct.left; + pnt.v = rct.top; + xi_move_to( win, pnt ); + pnt2.h = rct.left; + pnt2.v = rct.bottom - 1; + xi_draw_line( win, pnt2 ); + + xi_move_to( win, pnt ); + pnt2.h = rct.right - 1; + pnt2.v = rct.top; + xi_draw_line( win, pnt2 ); + + if ( height == 2 ) + { + pnt.h++; + pnt.v++; + xi_move_to( win, pnt ); + pnt2.h = pnt.h; + pnt2.v = rct.bottom - 2; + xi_draw_line( win, pnt2 ); + + xi_move_to( win, pnt ); + pnt2.h = rct.right - 2; + pnt2.v = pnt.v; + xi_draw_line( win, pnt2 ); + } + + /* draw lower right lines */ + cpen.fore_color = well ? color_light : color_dark; + XinWindowPenSet( win, &cpen ); + + pnt.h = rct.left; + pnt.v = rct.bottom - 1; + xi_move_to( win, pnt ); + pnt2.h = rct.right - 1; + pnt2.v = pnt.v; + xi_draw_line( win, pnt2 ); + + pnt.h = rct.right - 1; + pnt.v = rct.top; + xi_move_to( win, pnt ); + pnt2.h = pnt.h; + pnt2.v = rct.bottom; + xi_draw_line( win, pnt2 ); + + if ( height == 2 ) + { + pnt.h = rct.left + 1; + pnt.v = rct.bottom - 2;; + xi_move_to( win, pnt ); + pnt2.h = rct.right - 1; + pnt2.v = pnt.v; + xi_draw_line( win, pnt2 ); + + pnt.h = rct.right - 2; + pnt.v = rct.top + 1; + xi_move_to( win, pnt ); + pnt2.h = pnt.h; + pnt2.v = rct.bottom; + xi_draw_line( win, pnt2 ); + } + + XinWindowPenSet( win, &hollow_cpen ); + cbrush = white_cbrush; + cbrush.fore_color = color_ctrl; + XinWindowBrushSet( win, &cbrush ); + if ( height == 2 ) + { + rct.top += 2; + rct.left += 2; + rct.bottom -= 2; + rct.right -= 2; + } + else + { + rct.top++; + rct.left++; + rct.bottom--; + rct.right--; + } + + xi_draw_rect( win, &rct ); +} + +void +xi_draw_shaded_rect( XinWindow win, XinRect * rctp, BOOLEAN well, int height, + XinColor color_light, XinColor color_ctrl, XinColor color_dark ) +{ + XinRect rct; + XinPoint pnt, + pnt2; + XinPen cpen; + XinBrush cbrush; + + if ( !color_light ) + { + color_light = xi_get_pref( XI_PREF_COLOR_LIGHT ); + color_ctrl = xi_get_pref( XI_PREF_COLOR_CTRL ); + color_dark = xi_get_pref( XI_PREF_COLOR_DARK ); + } + cpen = black_cpen; + rct = *rctp; + XinWindowDrawModeSet( win, XinDrawModeCopy ); + + /* draw upper left lines */ + cpen.fore_color = well ? color_dark : color_light; + XinWindowPenSet( win, &cpen ); + pnt.h = rct.left; + pnt.v = rct.top; + xi_move_to( win, pnt ); + pnt2.h = rct.left; + pnt2.v = rct.bottom - 1; + xi_draw_line( win, pnt2 ); + + xi_move_to( win, pnt ); + pnt2.h = rct.right - 1; + pnt2.v = rct.top; + xi_draw_line( win, pnt2 ); + + if ( height == 2 ) + { + pnt.h++; + pnt.v++; + xi_move_to( win, pnt ); + pnt2.h = pnt.h; + pnt2.v = rct.bottom - 2; + xi_draw_line( win, pnt2 ); + + xi_move_to( win, pnt ); + pnt2.h = rct.right - 2; + pnt2.v = pnt.v; + xi_draw_line( win, pnt2 ); + } + + /* draw lower right lines */ + cpen.fore_color = well ? color_light : color_dark; + XinWindowPenSet( win, &cpen ); + + pnt.h = rct.left; + pnt.v = rct.bottom - 1; + xi_move_to( win, pnt ); + pnt2.h = rct.right - 1; + pnt2.v = pnt.v; + xi_draw_line( win, pnt2 ); + + pnt.h = rct.right - 1; + pnt.v = rct.top; + xi_move_to( win, pnt ); + pnt2.h = pnt.h; + pnt2.v = rct.bottom; + xi_draw_line( win, pnt2 ); + + if ( height == 2 ) + { + pnt.h = rct.left + 1; + pnt.v = rct.bottom - 2;; + xi_move_to( win, pnt ); + pnt2.h = rct.right - 1; + pnt2.v = pnt.v; + xi_draw_line( win, pnt2 ); + + pnt.h = rct.right - 2; + pnt.v = rct.top + 1; + xi_move_to( win, pnt ); + pnt2.h = pnt.h; + pnt2.v = rct.bottom; + xi_draw_line( win, pnt2 ); + } + + XinWindowPenSet( win, &hollow_cpen ); + cbrush = white_cbrush; + cbrush.fore_color = color_ctrl; + XinWindowBrushSet( win, &cbrush ); + if ( height == 2 ) + { + rct.top += 2; + rct.left += 2; + rct.bottom -= 2; + rct.right -= 2; + } + else + { + rct.top++; + rct.left++; + rct.bottom--; + rct.right--; + } + + XinWindowShadedRectDraw(win, &rct); +} + +void +xi_draw_checkmark( XinWindow win, XinRect * rctp ) +{ + XinWindowCheckMarkDraw( win, rctp ); +} + +void +xi_draw_3d_line( XinWindow win, XinPoint pnt1, XinPoint pnt2, BOOLEAN well ) +{ + XinColor color_light, + color_dark; + XinPoint pnt1x, + pnt2x; + XinPen cpen; + + color_light = xi_get_pref( XI_PREF_COLOR_LIGHT ); + color_dark = xi_get_pref( XI_PREF_COLOR_DARK ); + cpen = black_cpen; + XinWindowDrawModeSet( win, XinDrawModeCopy ); + + cpen.fore_color = well ? color_dark : color_light; + XinWindowPenSet( win, &cpen ); + xi_move_to( win, pnt1 ); + xi_draw_line( win, pnt2 ); + + pnt1x = pnt1; + pnt2x = pnt2; + if ( pnt1x.v == pnt2x.v ) + { + pnt1x.v++; + pnt2x.v++; + } + else + { + pnt1x.h++; + pnt2x.h++; + } + + cpen.fore_color = well ? color_light : color_dark; + XinWindowPenSet( win, &cpen ); + xi_move_to( win, pnt1x ); + xi_draw_line( win, pnt2x ); +} + +void +xi_draw_thick_rect( XinWindow win, XinRect * rctp, int width ) +{ + XinRect mrct; + int i; + + mrct = *rctp; + for ( i = 0; i < width; ++i ) + { + xi_draw_rect( win, &mrct ); + mrct.top++; + mrct.left++; + mrct.bottom--; + mrct.right--; + } +} + +void +xi_draw_diamond( XinWindow win, XinRect * rctp, BOOLEAN well, BOOLEAN black, BOOLEAN fill, + XinColor color ) +{ + XinPoint pnt1, + pnt2; + int half_width, + width; + XinRect rct; + XinColor color_light, + color_ctrl, + color_dark; + XinPen cpen; + + rct = *rctp; + width = ( rct.right - rct.left ) / 2; + width = width * 2 + 1; + half_width = width / 2 + 1; + rct.right = rct.left + width; + rct.bottom = rct.top + width; + + color_light = xi_get_pref( XI_PREF_COLOR_LIGHT ); + color_ctrl = xi_get_pref( XI_PREF_COLOR_CTRL ); + color_dark = xi_get_pref( XI_PREF_COLOR_DARK ); + + cpen = black_cpen; + cpen.fore_color = well ? color_dark : color_light; + if ( black ) + cpen.fore_color = XI_COLOR_BLACK; + if ( color ) + cpen.fore_color = color; + XinWindowPenSet( win, &cpen ); + XinWindowDrawModeSet( win, XinDrawModeCopy ); + + /* upper left */ + pnt1.h = rct.left; + pnt1.v = rct.top + half_width; + xi_move_to( win, pnt1 ); + pnt2.h = rct.left + half_width; + pnt2.v = rct.top; + xi_draw_line( win, pnt2 ); + + /* lower left */ + pnt1.h = rct.left; + pnt1.v = rct.top + half_width - 1; + xi_move_to( win, pnt1 ); + pnt2.h = rct.left + half_width - 1; + pnt2.v = rct.bottom - 1; + xi_draw_line( win, pnt2 ); + + cpen.fore_color = well ? color_light : color_dark; + if ( black ) + cpen.fore_color = XI_COLOR_BLACK; + if ( color ) + cpen.fore_color = color; + XinWindowPenSet( win, &cpen ); + + /* upper right */ + pnt1.h = rct.left + half_width; + pnt1.v = rct.top + 1; + xi_move_to( win, pnt1 ); + pnt2.h = rct.right; + pnt2.v = rct.top + half_width; + xi_draw_line( win, pnt2 ); + + /* lower right */ + pnt1.h = rct.left + half_width - 1; + pnt1.v = rct.bottom; + xi_move_to( win, pnt1 ); + pnt2.h = rct.right; + pnt2.v = rct.top + half_width - 1; + xi_draw_line( win, pnt2 ); + + if ( fill ) + { + int h, + v1, + v2, + hwm1; + XinPoint pnt1, + pnt2; + + v1 = rct.top + half_width - 1; + v2 = rct.top + half_width; + cpen.fore_color = color_ctrl; + XinWindowPenSet( win, &cpen ); + hwm1 = rct.left + half_width - 1; + for ( h = rct.left + 1; h <= rct.right - 2; ++h ) + { + pnt1.h = h; + pnt1.v = v1; + xi_move_to( win, pnt1 ); + pnt2.h = h; + pnt2.v = v2; + xi_draw_line( win, pnt2 ); + if ( h < hwm1 ) + { + v1--; + v2++; + } + else + { + v1++; + v2--; + } + } + } +} + +void +xi_draw_3d_diamond( XinWindow win, XinRect * rctp, BOOLEAN well, BOOLEAN black, int height, + XinColor color ) +{ + XinRect rct; + int i; + + rct = *rctp; + for ( i = 0; i < height; ++i ) + { + xi_draw_diamond( win, &rct, well, black, ( BOOLEAN ) ( i == height - 1 ), color ); + rct.top++; + rct.left++; + rct.bottom--; + rct.right--; + if ( rct.top > rct.bottom || rct.left > rct.right ) + break; + } +} + +#ifdef NEED_MEMMOVE +char * +memmove( register char *d, register char *s, long n ) +{ + char *dst = d; + + /* remove when MEDIUM goes away */ + if ( d < s ) + while ( n-- > 0 ) + *d++ = *s++; + else + { + d += ( int ) n - 1; + s += ( int ) n - 1; + while ( n-- > 0 ) + *d-- = *s--; + } + return dst; +} + +#endif + +#if XIWS != XIWS_WM +void +dbg_rct( char *tag, XinRect * rct ) +{ + char buf[100]; + + sprintf( buf, + "%s: top %d left %d bottom %d right %d", tag, rct->top, rct->left, + rct->bottom, rct->right ); + xi_dbg( buf ); +} + +#endif + +void +xi_set_cur_window( XinWindow win ) +{ + cur_window = win; + cur_itf = xi_get_itf( win ); + if ( cur_itf ) + { + cur_delta_x = cur_itf->v.itf->delta_x; + cur_delta_y = cur_itf->v.itf->delta_y; + } + else + { + cur_delta_x = 0; + cur_delta_y = 0; + } +} + +void +xi_dbg( char *buf ) +{ + XinDebugPrintf( buf ); +} + +void +xi_even_fu( int *f ) +{ + *f = ( *f * XI_FU_MULTIPLE + XI_FU_MULTIPLE / 2 ) / XI_FU_MULTIPLE; +} + +void +xi_even_fu_pnt( XinPoint * p ) +{ + p->h = ( p->h * XI_FU_MULTIPLE + XI_FU_MULTIPLE / 2 ) / XI_FU_MULTIPLE; + p->v = ( p->v * XI_FU_MULTIPLE + XI_FU_MULTIPLE / 2 ) / XI_FU_MULTIPLE; +} + +int +xi_get_fu_width( XI_OBJ * itf ) +{ + if ( itf ) + return itf->v.itf->fu_width; + else + return xi_get_fu_width_font( xi_get_system_font( ) ); +} + +int +xi_get_fu_height( XI_OBJ * itf ) +{ + if ( itf ) + return itf->v.itf->fu_height; + else + return xi_get_fu_height_font( xi_get_system_font( ) ); +} + +int +xi_get_fu_width_font( XinFont * font ) +{ + int leading, + ascent, + descent, + char_width; + + xi_get_font_metrics_font( font, &leading, &ascent, &descent, &char_width ); + return char_width; +} + +int +xi_get_fu_height_font( XinFont * font ) +{ + int leading, + ascent, + descent, + char_width; + int height; + + xi_get_font_metrics_font( font, &leading, &ascent, &descent, &char_width ); + height = leading + ascent + descent + STX_VERT_FUDGE; + return height; +} + +void +xi_fu_to_pu_font( XinFont * font, XinPoint * pnts, int nbr_pnts ) +{ + int leading, + ascent, + descent, + char_width; + int height; + + xi_get_font_metrics_font( font, &leading, &ascent, &descent, &char_width ); + height = leading + ascent + descent + STX_VERT_FUDGE; + while ( nbr_pnts != 0 ) + { + pnts->v = ( short ) ( ( ( long ) pnts->v * ( long ) height ) / ( long ) XI_FU_MULTIPLE ); + pnts->h = ( short ) ( ( ( long ) pnts->h * ( long ) char_width ) / ( long ) XI_FU_MULTIPLE ); + pnts++; + nbr_pnts--; + } +} + +BOOLEAN +font_compare( XinFont * f1, XinFont * f2 ) +{ + return XinFontCompare( f1, f2 ); +} + +void +xi_get_font_metrics_font( XinFont * font, int *leading, + int *ascent, int *descent, int *char_width ) +{ + FONT_INFO* fi; + int i; + XinWindow win = (XinWindow)0L; + BOOLEAN close_win = FALSE; + XinRect rct; + + for ( i = 0, fi = font_info; i < font_info_cnt; ++i, ++fi ) + { + if ( font_compare( fi->font, font ) ) + { + *leading = fi->leading; + *ascent = fi->ascent; + *descent = fi->descent; + *char_width = fi->char_width; + return; + } + } + ++font_info_cnt; + if ( font_info ) + font_info = ( FONT_INFO * ) xi_tree_realloc( font_info, sizeof( FONT_INFO ) * font_info_cnt ); + else + font_info = ( FONT_INFO * ) xi_tree_malloc( sizeof( FONT_INFO ) * font_info_cnt, ( void * ) NULL ); + fi = &font_info[font_info_cnt - 1]; + XinFontCopy( &fi->font, font ); + if ( !XinFontIsMapped( fi->font ) ) + { + rct.top = -200; + rct.left = -200; + rct.bottom = -100; + rct.right = -100; + { + XinWindowDef Def; + + MEMCLEAR( Def ); + Def.type = XinWindowTypeDocument; + Def.border_style = XinBorderFixed; + Def.p_rect = &rct; + Def.title = ""; + Def.vertical_scroll_bar = FALSE; + Def.horizontal_scroll_bar = FALSE; + Def.close_button = FALSE; + Def.visible = FALSE; + Def.enabled = FALSE; + Def.parent = XinWindowTaskGet( ); + win = XinWindowCreate( &Def ); + } + close_win = TRUE; + XinWindowFontMap( win, font ); + } + { + int tl, + ta, + td; + + XinFontMetricsGet( font, &tl, &ta, &td ); + fi->leading = tl; + fi->ascent = ta; + fi->descent = td; + } + fi->char_width = XinFontTextWidthGet( font, + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + -1 ) / 52; + if ( close_win ) + { + XinFontUnmap( font ); /* RGM: Font unmap hack */ + XinWindowDestroy( win ); + } + *leading = fi->leading; + *ascent = fi->ascent; + *descent = fi->descent; + *char_width = fi->char_width; +} + +/********************************************************************/ +/* FUNCTIONS THAT NEED TRANSPOSING */ + +static void +ppnt_to_vpnt( XinWindow win, XinPoint * pnt ) +{ + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + + itf = xi_get_itf( win ); + if ( itf ) + { + itf_data = itf->v.itf; + pnt->h += itf_data->delta_x; + pnt->v += itf_data->delta_y; + } +} + +static void +vpnt_to_ppnt( XinWindow win, XinPoint * pnt ) +{ + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + + itf = xi_get_itf( win ); + if ( itf ) + { + itf_data = itf->v.itf; + pnt->h -= itf_data->delta_x; + pnt->v -= itf_data->delta_y; + } +} + +static void +vrct_to_prct( XinWindow win, XinRect * rct ) +{ + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + + itf = xi_get_itf( win ); + if ( itf ) + { + itf_data = itf->v.itf; + rct->left -= itf_data->delta_x; + rct->right -= itf_data->delta_x; + rct->top -= itf_data->delta_y; + rct->bottom -= itf_data->delta_y; + } +} + +static void +move_controls( XI_OBJ * xi_obj ) +{ + XI_OBJ **objlist; + int n; + XinRect rct; + + switch ( xi_obj->type ) + { + case XIT_ITF: + if ( !xi_obj->v.itf->half_baked ) + XinWindowPaintForce( xi_obj->v.itf->xin_win ); + break; +#ifdef XI_USE_TX_SUPPORT + case XIT_FIELD: + if ( xi_get_pref( XI_PREF_USE_TX_SUPPORT ) ) + xi_tx_edit_move( xi_obj ); + break; +#endif + case XIT_LIST: + { + XI_LIST_DATA *list_data; + XI_ITF_DATA *itf_data; + + itf_data = xi_obj->itf->v.itf; + list_data = xi_obj->v.list; + if ( list_data->sb_win ) + { + xi_get_sb_rect( xi_obj, &rct ); + xi_offset_rect( &rct, -itf_data->delta_x, -itf_data->delta_y ); + XinWindowRectSet( list_data->sb_win, &rct ); + } + if ( list_data->hsb_win ) + { + xi_get_hsb_rect( xi_obj, &rct ); + xi_offset_rect( &rct, -itf_data->delta_x, -itf_data->delta_y ); + XinWindowRectSet( list_data->hsb_win, &rct ); + } + break; + } + case XIT_BTN: + { + XinRect rct; + XI_ITF_DATA *itf_data; + XI_BTN_DATA *btn_data; + + btn_data = xi_obj->v.btn; + if ( btn_data->btnctl ) + { + itf_data = xi_obj->itf->v.itf; + rct = btn_data->rct; + xi_offset_rect( &rct, -itf_data->delta_x, -itf_data->delta_y ); + XinWindowRectSet( btn_data->btnctl, &rct ); + } + break; + } + default: + break; + } + objlist = xi_get_member_list( xi_obj, &n ); + for ( ; n > 0; n--, objlist++ ) + move_controls( *objlist ); + if ( xi_obj->type == XIT_ITF ) + xi_set_clip( xi_obj->v.itf->xin_win, NULL ); +} + + +void +xi_adjust_sb_vir_itf( XinWindow win, XI_OBJ * itf ) +{ + XinRect rct; + XI_ITF_DATA *itf_data; + + itf_data = itf->v.itf; + XinWindowRectGet( win, &rct ); + itf_data->win_xi_pnt.v = rct.bottom - rct.top; + itf_data->win_xi_pnt.h = rct.right - rct.left; + xi_pu_to_fu( itf, &itf_data->win_xi_pnt, 1 ); + xi_even_fu_pnt( &itf_data->win_xi_pnt ); + if ( itf_data->win_xi_pnt.h + itf_data->phys_xi_pnt.h > + itf_data->max_xi_pnt.h || + itf_data->win_xi_pnt.v + itf_data->phys_xi_pnt.v > + itf_data->max_xi_pnt.v ) + { + XinPoint p; + int old_delta_x, + old_delta_y; + + if ( itf_data->win_xi_pnt.h + itf_data->phys_xi_pnt.h > + itf_data->max_xi_pnt.h ) + itf_data->phys_xi_pnt.h = itf_data->max_xi_pnt.h - + itf_data->win_xi_pnt.h; + if ( itf_data->phys_xi_pnt.h < 0 ) + itf_data->phys_xi_pnt.h = 0; + if ( itf_data->win_xi_pnt.v + itf_data->phys_xi_pnt.v > + itf_data->max_xi_pnt.v ) + itf_data->phys_xi_pnt.v = itf_data->max_xi_pnt.v - + itf_data->win_xi_pnt.v; + if ( itf_data->phys_xi_pnt.v < 0 ) + itf_data->phys_xi_pnt.v = 0; + p.h = itf_data->phys_xi_pnt.h; + p.v = itf_data->phys_xi_pnt.v; + xi_fu_to_pu( itf, &p, 1 ); + cur_delta_x = p.h; + cur_delta_y = p.v; + old_delta_x = itf_data->delta_x; + old_delta_y = itf_data->delta_y; + itf_data->delta_x = cur_delta_x; + itf_data->delta_y = cur_delta_y; + xi_caret_suspend( win ); + if ( old_delta_x != cur_delta_x || old_delta_y != cur_delta_y ) + xi_invalidate_rect( win, NULL ); + move_controls( itf ); + xi_caret_restore( win ); + } + set_sb_positions( itf ); +} + + +BOOLEAN +xi_eh( XinWindow win, XinEvent * ep ) +{ + switch ( ep->type ) + { + case XinEventPaint: + update_pending = FALSE; + break; + case XinEventCharacter: + if ( update_pending && ( ep->v.character.ch == XI_KEY_UP || ep->v.character.ch == XI_KEY_DOWN ) ) + return FALSE; + break; + case XinEventResize: + { + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + XinRect rct; + + itf = xi_get_itf( win ); + if ( !itf ) + break; + itf_data = itf->v.itf; + if ( itf_data->size_font_to_win ) + { + XinRect old_win_rct; + int bottom, + right; + XinFont *itf_font; + + XinWindowRectGet( win, &rct ); + old_win_rct = itf->v.itf->original_win_rct; + bottom = old_win_rct.bottom; + right = old_win_rct.right; + itf_font = itf_data->font; + if ( itf_font ) + { + int point_size, + point_size2; + + point_size = itf->v.itf->original_font_size; + point_size = ( point_size * rct.bottom + bottom / 2 ) / bottom; + point_size2 = itf->v.itf->original_font_size; + point_size2 = ( point_size2 * rct.right + right / 2 ) / right; + XinFontSizeSet( itf_font, point_size2 - 1 ); + recalc_metrics( itf ); + xi_invalidate_rect( xi_get_window( itf ), NULL ); + } + break; + } + if ( itf_data->virtual_itf ) + xi_adjust_sb_vir_itf( win, itf ); + break; + } + case XinEventMouseDown: + case XinEventMouseUp: + case XinEventMouseDouble: + case XinEventMouseMove: + ppnt_to_vpnt( win, &ep->v.mouse.where ); + break; + case XinEventHScroll: + { + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + int delta_x = 0, + old, + d; + + itf = xi_get_itf( win ); + if ( !itf ) + break; + itf_data = itf->v.itf; + if ( !itf_data->virtual_itf ) + break; + switch ( ep->v.scroll.action ) + { + case XinScrollBarActionLineUp: + delta_x = -4 * XI_FU_MULTIPLE; + break; + case XinScrollBarActionLineDown: + delta_x = 4 * XI_FU_MULTIPLE; + break; + case XinScrollBarActionPageUp: + delta_x = -10 * XI_FU_MULTIPLE; + break; + case XinScrollBarActionPageDown: + delta_x = 10 * XI_FU_MULTIPLE; + break; + case XinScrollBarActionThumb: + { + int oldp, + newp; + + oldp = itf_data->phys_xi_pnt.h; + newp = ( int ) ( ( long ) ep->v.scroll.position * + ( ( long ) itf_data->max_xi_pnt.h - + ( long ) itf_data->win_xi_pnt.h ) / 100L ); + xi_even_fu( &newp ); + delta_x = newp - oldp; + break; + } + case XinScrollBarActionThumbTrack: + delta_x = 0; + break; + default: + break; + } + old = itf_data->phys_xi_pnt.h; + itf_data->phys_xi_pnt.h += delta_x; + itf_data->phys_xi_pnt.h = + min( itf_data->phys_xi_pnt.h, itf_data->max_xi_pnt.h - + itf_data->win_xi_pnt.h ); + itf_data->phys_xi_pnt.h = + max( itf_data->phys_xi_pnt.h, 0 ); + d = itf_data->phys_xi_pnt.h - old; + + /* d is now the delta in form units */ + if ( d ) + { + XinRect client_rct; + XinPoint pnt; + + XinWindowPaintForce( win ); + XinWindowRectGet( win, &client_rct ); + pnt.h = itf_data->phys_xi_pnt.h; + xi_fu_to_pu( itf, &pnt, 1 ); + cur_delta_x = pnt.h; + pnt.h = d; + xi_fu_to_pu( itf, &pnt, 1 ); + xi_caret_suspend( win ); + do_vir_pan_event( itf, pnt.h, 0, TRUE ); + itf_data->delta_x += pnt.h; + XinWindowRectScroll( win, &client_rct, -pnt.h, 0 ); + set_sb_positions( itf ); + move_controls( itf ); + do_vir_pan_event( itf, pnt.h, 0, FALSE ); + xi_caret_restore( win ); + } + break; + } + case XinEventVScroll: + { + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + int delta_y = 0, + old, + d; + + itf = xi_get_itf( win ); + if ( !itf ) + break; + itf_data = itf->v.itf; + if ( !itf_data->virtual_itf ) + break; + switch ( ep->v.scroll.action ) + { + case XinScrollBarActionLineUp: + delta_y = -XI_FU_MULTIPLE; + break; + case XinScrollBarActionLineDown: + delta_y = XI_FU_MULTIPLE; + break; + case XinScrollBarActionPageUp: + delta_y = -10 * XI_FU_MULTIPLE; + break; + case XinScrollBarActionPageDown: + delta_y = 10 * XI_FU_MULTIPLE; + break; + case XinScrollBarActionThumb: + { + int oldp, + newp; + + oldp = itf_data->phys_xi_pnt.v; + newp = ( int ) ( ( long ) ep->v.scroll.position * + ( ( long ) itf_data->max_xi_pnt.v - + ( long ) itf_data->win_xi_pnt.v ) / 100L ); + xi_even_fu( &newp ); + delta_y = newp - oldp; + break; + } + case XinScrollBarActionThumbTrack: + delta_y = 0; + break; + default: + break; + } + old = itf_data->phys_xi_pnt.v; + itf_data->phys_xi_pnt.v += delta_y; + itf_data->phys_xi_pnt.v = + min( itf_data->phys_xi_pnt.v, itf_data->max_xi_pnt.v - + itf_data->win_xi_pnt.v ); + itf_data->phys_xi_pnt.v = + max( itf_data->phys_xi_pnt.v, 0 ); + d = itf_data->phys_xi_pnt.v - old; + if ( d ) + { + XinRect client_rct; + XinPoint pnt; + + XinWindowPaintForce( win ); + XinWindowRectGet( win, &client_rct ); + pnt.v = itf_data->phys_xi_pnt.v; + xi_fu_to_pu( itf, &pnt, 1 ); + cur_delta_y = pnt.v; + pnt.v = d; + xi_fu_to_pu( itf, &pnt, 1 ); + xi_caret_suspend( win ); + do_vir_pan_event( itf, 0, pnt.v, TRUE ); + itf_data->delta_y += pnt.v; + XinWindowRectScroll( win, &client_rct, 0, -pnt.v ); + set_sb_positions( itf ); + move_controls( itf ); + do_vir_pan_event( itf, 0, pnt.v, FALSE ); + xi_caret_restore( win ); + } + break; + } + default: + break; + } + return TRUE; +} + +void +xi_vir_pan( XI_OBJ * itf, int delta_x, int delta_y ) +{ + XinRect cr; + XinWindow win; + XI_ITF_DATA *itf_data; + XinPoint pf, + p; + int old; + + pf.h = delta_x; + pf.v = delta_y; + itf_data = itf->v.itf; + win = xi_get_window( itf ); + XinWindowRectGet( win, &cr ); + XinWindowPaintForce( win ); + + /* clip y delta to appropriate bounding */ + old = itf_data->phys_xi_pnt.v; + itf_data->phys_xi_pnt.v += pf.v; + itf_data->phys_xi_pnt.v = + min( itf_data->phys_xi_pnt.v, itf_data->max_xi_pnt.v - + itf_data->win_xi_pnt.v ); + if ( itf_data->phys_xi_pnt.v < 0 ) + itf_data->phys_xi_pnt.v = 0; + pf.v = itf_data->phys_xi_pnt.v - old; + + /* clip x delta to appropriate bounding */ + old = itf_data->phys_xi_pnt.h; + itf_data->phys_xi_pnt.h += pf.h; + itf_data->phys_xi_pnt.h = + min( itf_data->phys_xi_pnt.h, itf_data->max_xi_pnt.h - + itf_data->win_xi_pnt.h ); + if ( itf_data->phys_xi_pnt.h < 0 ) + itf_data->phys_xi_pnt.h = 0; + pf.h = itf_data->phys_xi_pnt.h - old; + + /* convert to pixel coordinates */ + p = pf; + xi_fu_to_pu( itf, &p, 1 ); + + /* add to current delta x and y */ + cur_delta_y += p.v; + cur_delta_x += p.h; + + /* do the virtual pan */ + xi_caret_suspend( win ); + do_vir_pan_event( itf, p.h, p.v, TRUE ); + itf_data->delta_y = cur_delta_y; + itf_data->delta_x = cur_delta_x; + XinWindowRectScroll( win, &cr, -p.h, -p.v ); + set_sb_positions( itf ); + move_controls( itf ); + do_vir_pan_event( itf, p.h, p.v, FALSE ); + xi_caret_restore( win ); +} + +void +xi_make_obj_visible( XI_OBJ * xi_obj ) +{ + XinRect or, + cr, + cr2; + XI_OBJ *itf; + XI_ITF_DATA *itf_data; + XinWindow win; + int dt, + db, + dl, + dr, + dh, + dv; + XinPoint p, + pf, + pp; + int pref_h, + pref_v; + + switch ( xi_obj->type ) + { + case XIT_ITF: + case XIT_GROUP: + case XIT_FORM: + case XIT_LIST: + case XIT_COLUMN: + case XIT_CONTAINER: + return; + default: + break; + } + pref_h = ( int ) xi_get_pref( XI_PREF_VIR_SP_H ); + pref_v = ( int ) xi_get_pref( XI_PREF_VIR_SP_V ); + itf = xi_obj->itf; + itf_data = itf->v.itf; + win = xi_get_window( itf ); + xi_set_cur_window( win ); + XinWindowRectGet( win, &cr ); + pp.v = itf_data->max_xi_pnt.v; + pp.h = itf_data->max_xi_pnt.h; + xi_fu_to_pu( xi_obj->itf, &pp, 1 ); + xi_get_rect( xi_obj, &or ); + or.top -= pref_v; + if ( or.top < 0 ) + or.top = 0; + or.bottom += pref_v; + if ( or.bottom > pp.v ) + or.bottom = pp.v; + or.left -= pref_h; + if ( or.left < 0 ) + or.left = 0; + or.right += pref_h; + if ( or.right > pp.h ) + or.right = pp.h; + cr2 = cr; + cr2.left += itf_data->delta_x; + cr2.right += itf_data->delta_x; + cr2.top += itf_data->delta_y; + cr2.bottom += itf_data->delta_y; + dr = or.right - cr2.right; /* positive if not ok */ + dr = max( 0, dr ); + dr = min( dr, pp.h ); + db = or.bottom - cr2.bottom; /* positive if not ok */ + db = max( 0, db ); + db = min( db, pp.v ); + dl = cr2.left - or.left; /* positive if not ok */ + dl = max( 0, dl ); + dt = cr2.top - or.top; /* positive if not ok */ + dt = max( 0, dt ); + if ( dl && dr ) + dr = 0; + if ( db && dt ) + db = 0; + if ( dl ) + dh = -dl; + else + dh = dr; + if ( dt ) + dv = -dt; + else + dv = db; + p.h = dh; + p.v = dv; + xi_pu_to_fu( xi_obj->itf, &p, 1 ); + xi_even_fu_pnt( &p ); + pf = p; + xi_fu_to_pu( xi_obj->itf, &p, 1 ); + if ( p.h || p.v ) + { + XinWindowPaintForce( win ); + itf_data->phys_xi_pnt.v += pf.v; + itf_data->phys_xi_pnt.h += pf.h; + cur_delta_y += p.v; + cur_delta_x += p.h; + xi_caret_suspend( win ); + do_vir_pan_event( itf, p.h, p.v, TRUE ); + itf_data->delta_y = cur_delta_y; + itf_data->delta_x = cur_delta_x; + XinWindowRectScroll( win, &cr, -p.h, -p.v ); + set_sb_positions( itf ); + move_controls( itf ); + do_vir_pan_event( itf, p.h, p.v, FALSE ); + xi_caret_restore( win ); + } +} + +void +xi_scroll_rect( XinWindow win, XinRect * rctp, int dh, int dv ) +{ + XinRect r; + + xi_set_cur_window( win ); + r = *rctp; + vrct_to_prct( win, &r ); + if (dh == 0 && dv == 0) + update_pending = FALSE; + else + update_pending = TRUE; + XinWindowRectScroll( win, &r, dh, dv ); +} + +static void +xi_caret_suspend( XinWindow win ) +{ + XI_ITF_DATA *itf_data; + + itf_data = xi_get_itf( win )->v.itf; + if ( itf_data->caret_is_on ) + { + XinWindowCaretOff( win ); + } +} + +static void +xi_caret_restore( XinWindow win ) +{ + XI_ITF_DATA *itf_data; + XinPoint p; + XinDrawTools dt; + + itf_data = xi_get_itf( win )->v.itf; + if ( itf_data->caret_is_on ) + { + int x, + y; + XinRect local_clip; + + p.h = itf_data->caret_x; + p.v = itf_data->caret_y; + vpnt_to_ppnt( win, &p ); + x = p.h; + y = p.v; + local_clip = itf_data->caret_clip; + vrct_to_prct( win, &local_clip ); + XinWindowDrawToolsGet( win, &dt ); + XinWindowCaretOn( win, x, y, itf_data->caret_height, dt.text_back_color, + &local_clip ); + } +} + +void +xi_invalidate_rect( XinWindow win, XinRect * rct ) +{ + XinRect r, + cr, + dr; + + if ( rct != NULL && ( rct->top >= rct->bottom || rct->left >= rct->right ) ) + return; + + if ( !rct ) + { + XinWindowRectInvalidate( win, NULL ); + return; + } + r = *rct; + vrct_to_prct( win, &r ); + + XinWindowRectGet( win, &cr ); + if ( xi_rect_intersect( &dr, &r, &cr ) ) + { + update_pending = TRUE; + XinWindowRectInvalidate( win, &r ); + } +} + +BOOLEAN +xi_XinWindowPaintNeeds( XinWindow win, XinRect * rct ) +{ + XinRect r; + + r = *rct; + vrct_to_prct( win, &r ); + return XinWindowPaintNeeds( win, &r ); +} + +void +xi_draw_icon( XinWindow win, int x, int y, int rid, XinColor fore_color, + XinColor back_color ) +{ + if ( rid ) + { + XinPoint p; + + xi_set_cur_window( win ); + p.h = x; + p.v = y; + vpnt_to_ppnt( win, &p ); + XinWindowIconDraw( win, p.h, p.v, rid, fore_color, back_color ); + } +} + +#if XIWS == XIWS_WM +static void +adjust_point( short *p ) +{ + *p = ( ( *p + 4 ) / 8 ) * 8; +} + +#endif + +void +xi_draw_rect( XinWindow win, XinRect * rctp ) +{ + if ( rctp->top >= rctp->bottom || rctp->left >= rctp->right ) + return; + { + XinRect r; + +#if XIWS == XIWS_WM + XinDrawTools ct; + + r = *rctp; + adjust_point( &r.top ); + adjust_point( &r.left ); + adjust_point( &r.bottom ); + adjust_point( &r.right ); + xi_set_cur_window( win ); + vrct_to_prct( win, &r ); + XinWindowDrawToolsGet( win, &ct ); + if ( ct.mode == XinDrawModeXor && !xi_is_rect_empty( &r ) ) + ct.brush.color = XI_COLOR_BLACK; + if ( ct.brush.pat == XinPatternHollow ) + ct.brush.color = ct.back_color; + XinWindowDrawToolsSet( win, &ct ); + XinWindowRectDraw( win, &r ); +#else + r = *rctp; + xi_set_cur_window( win ); + vrct_to_prct( win, &r ); + XinWindowRectDraw( win, &r ); +#endif + } +} + +void +xi_draw_roundrect( XinWindow win, XinRect * rctp, int rh, int rv ) +{ + if ( rctp->top >= rctp->bottom || rctp->left >= rctp->right ) + return; + { + XinRect r; + +#if XIWS == XIWS_WM + XinDrawTools ct; + + r = *rctp; + adjust_point( &r.top ); + adjust_point( &r.left ); + adjust_point( &r.bottom ); + adjust_point( &r.right ); + xi_set_cur_window( win ); + vrct_to_prct( win, &r ); + XinWindowDrawToolsGet( win, &ct ); + if ( ct.mode == XinDrawModeXor && !xi_is_rect_empty( &r ) ) + ct.brush.color = XI_COLOR_BLACK; + if ( ct.brush.pat == XinPatternHollow ) + ct.brush.color = ct.back_color; + XinWindowDrawToolsSet( win, &ct ); + XinWindowRoundRectDraw( win, &r, radius, radius ); +#else + r = *rctp; + xi_set_cur_window( win ); + vrct_to_prct( win, &r ); + XinWindowRoundRectDraw( win, &r, rh, rv ); +#endif + } +} + +void +xi_move_to( XinWindow win, XinPoint pnt ) +{ + xi_set_cur_window( win ); + vpnt_to_ppnt( win, &pnt ); + XinWindowLineMoveTo( win, &pnt ); +} + +void +xi_draw_line( XinWindow win, XinPoint pnt ) +{ + xi_set_cur_window( win ); + vpnt_to_ppnt( win, &pnt ); + XinWindowLineDraw( win, &pnt ); +} + +static BOOLEAN +xi_is_rect_empty( XinRect * r ) +{ + BOOLEAN h_empty = ( r->left >= r->right ); + BOOLEAN v_empty = ( r->top >= r->bottom ); + + return h_empty || v_empty; +} + + +BOOLEAN +xi_rect_intersect( XinRect * rctp, XinRect * rctp1, XinRect * rctp2 ) +{ + XinRect r, + r2, + *rpnt; + + if ( rctp == NULL ) + rpnt = &r; + else + rpnt = rctp; + rpnt->left = max( rctp1->left, rctp2->left ); + rpnt->top = max( rctp1->top, rctp2->top ); + rpnt->right = min( rctp1->right, rctp2->right ); + rpnt->bottom = min( rctp1->bottom, rctp2->bottom ); + r2 = *rpnt; + return !xi_is_rect_empty( &r2 ); +} + + +/* Functions moved from XI.C because MPW cannot have too much code in one module. */ + +void +xi_menu_enable( XI_OBJ * itf, int tag, BOOLEAN enable ) +{ + XI_OBJ *xi_obj; + + XinWindow win; + + win = xi_get_window( itf ); + XinWindowMenuItemEnable( win, ( short ) tag, enable ); + xi_obj = xi_get_obj( itf, tag ); + if ( xi_obj != NULL && xi_obj->type == XIT_BTN ) + { + if ( enable ) + xi_set_attrib( xi_obj, xi_get_attrib( xi_obj ) | XI_ATR_ENABLED ); + else + xi_set_attrib( xi_obj, xi_get_attrib( xi_obj ) & ~XI_ATR_ENABLED ); + } +} + +void +xi_set_bitmap( XI_OBJ* xi_obj, XI_BITMAP* bitmap ) +{ + switch ( xi_obj->type ) + { + case XIT_CELL: + if ( !xi_obj->v.cell.is_vert_scrolled ) + lm_set_bitmap( xi_obj->parent->v.list->lm, bitmap, + xi_obj->v.cell.row, xi_obj->v.cell.column ); + break; + case XIT_BTN: + { + XI_BTN_DATA *bd; + XI_BITMAP* new_bitmap; + + bd = xi_obj->v.btn; + new_bitmap = xi_bitmap_copy( bitmap ); + xi_bitmap_destroy( bd->up_bitmap ); + bd->up_bitmap = new_bitmap; + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &bd->rct ); + break; + } + case XIT_COLUMN: + lm_set_column_bitmap( xi_obj->parent->v.list->lm, bitmap, xi_obj->cid ); + break; + default: + XinError( 20088, XinSeverityFatal, 0L ); + break; + } +} + +void +xi_set_down_bitmap( XI_OBJ * xi_obj, XI_BITMAP * bitmap ) +{ + switch ( xi_obj->type ) + { + case XIT_BTN: + { + XI_BTN_DATA *bd; + XI_BITMAP* new_bitmap; + + bd = xi_obj->v.btn; + new_bitmap = xi_bitmap_copy( bitmap ); + xi_bitmap_destroy( bd->down_bitmap ); + bd->down_bitmap = new_bitmap; + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &bd->rct ); + break; + } + default: + XinError( 20088, XinSeverityFatal, 0L ); + break; + } +} + +void +xi_set_icon( XI_OBJ * xi_obj, int icon_rid, int down_icon_rid ) +{ + switch ( xi_obj->type ) + { +case XIT_CELL: + if ( !xi_obj->v.cell.is_vert_scrolled ) + lm_set_icon( xi_obj->parent->v.list->lm, icon_rid, + xi_obj->v.cell.row, xi_obj->v.cell.column ); + break; + case XIT_BTN: + { + XI_BTN_DATA *bd; + + bd = xi_obj->v.btn; + bd->up_icon_rid = icon_rid; + bd->down_icon_rid = down_icon_rid; + xi_invalidate_rect( xi_obj->itf->v.itf->xin_win, &bd->rct ); + break; + } + case XIT_COLUMN: + { + lm_set_column_icon( xi_obj->parent->v.list->lm, icon_rid, xi_obj->cid ); + break; + } + default: + XinError( 20088, XinSeverityFatal, 0L ); + break; + } +} + +XinRect * +xi_get_xi_rct( XI_OBJ * xi_obj, XinRect * xi_rct ) +{ + int fu_width, + fu_height; + + fu_width = xi_get_fu_width( xi_obj ); + fu_height = xi_get_fu_height( xi_obj ); + switch ( xi_obj->type ) + { + case XIT_ITF: + { + XinRect r; + + XinWindowRectGet( xi_get_window( xi_obj ), &r ); + xi_rct->top = 0; + xi_rct->left = 0; + xi_rct->bottom = ( r.bottom / fu_height ) * XI_FU_MULTIPLE; + xi_rct->right = ( r.right / fu_width ) * XI_FU_MULTIPLE; + return xi_rct; + } + default: + return NULL; + } +} + +static void +recalc_metrics( XI_OBJ * xi_obj ) +{ + int i; + + switch ( xi_obj->type ) + { + case XIT_ITF: + { + XI_ITF_DATA *itf_data; + + itf_data = xi_obj->v.itf; + + /* recalculate fu_width and fu_height */ + itf_data->fu_height = xi_get_fu_height_font( itf_data->font ); + itf_data->fu_width = xi_get_fu_width_font( itf_data->font ); + + break; + } + case XIT_TEXT: + { + XI_TEXT_DATA *text_data; + + text_data = xi_obj->v.text; + + text_data->rct = text_data->xi_rct; + xi_fu_to_pu( xi_obj->itf, ( XinPoint * ) & text_data->rct, 2 ); + break; + } + case XIT_RECT: + { + XI_RECT_DATA *rect_data; + + rect_data = xi_obj->v.rect; + + rect_data->rct = rect_data->xi_rct; + xi_fu_to_pu( xi_obj->itf, ( XinPoint * ) & rect_data->rct, 2 ); + break; + } + case XIT_LINE: + { + XI_LINE_DATA *line_data; + + line_data = xi_obj->v.line; + + line_data->pnt1 = line_data->xi_pnt1; + line_data->pnt2 = line_data->xi_pnt2; + + xi_fu_to_pu( xi_obj->itf, &line_data->pnt1, 1 ); + xi_fu_to_pu( xi_obj->itf, &line_data->pnt2, 1 ); + + break; + } + case XIT_LIST: + lm_recalc_metrics( xi_obj->v.list->lm ); + + /* TODO recalc sbb_rct, sb_rct, hsb_rct */ + + break; + case XIT_COLUMN: + break; + case XIT_FIELD: + { + XI_FIELD_DATA *field_data; + int btn_dim_x, + btn_dim_x2, + fu_width, + fu_height, + edit_height, + btn_space; + XinWindow itf_win; + STX_DATA *stxp; + int leading, + ascent, + descent, + font_height; + + field_data = xi_obj->v.field; + stxp = ( STX_DATA * ) field_data->stx; + if ( !field_data->font_set ) + stxp->font = xi_obj->itf->v.itf->font; + itf_win = xi_get_window( xi_obj->itf ); + fu_width = xi_get_fu_width( xi_obj->itf ); + fu_height = xi_get_fu_height( xi_obj->itf ); + XinWindowFontMap( itf_win, stxp->font ); + XinFontMetricsGet( stxp->font, &leading, &ascent, &descent ); + font_height = ascent + leading + descent; + edit_height = font_height + ( 2 * EDIT_BORDER_WIDTH_Y ) + + ( 2 * EDIT_BORDER_SPACE_Y ); + if ( field_data->xi_rct.top || field_data->xi_rct.left || + field_data->xi_rct.bottom || field_data->xi_rct.right ) + { + stxp->rct = field_data->xi_rct; + if ( ( stxp->rct.bottom - stxp->rct.top ) <= + XI_FU_MULTIPLE ) + { + xi_fu_to_pu( xi_obj->itf, ( XinPoint * ) & stxp->rct, 2 ); + stxp->rct.bottom = stxp->rct.top + edit_height; + } + else + { + xi_fu_to_pu( xi_obj->itf, ( XinPoint * ) & stxp->rct, 2 ); + stxp->rct.bottom -= BORDER_SPACE_Y; + /* TODO move text edit object */ + } + } + else + { + XinPoint p; + XinRect rct; + + p = field_data->xi_pnt; + xi_fu_to_pu( xi_obj->itf, &p, 1 ); + rct.left = p.h; + rct.top = p.v; + rct.right = p.h + ( field_data->field_width / XI_FU_MULTIPLE ) * fu_width + + 2 * BORDER_WIDTH_X + 2 * BORDER_SPACE_X; + rct.bottom = p.v + edit_height; + stxp->rct = rct; + } + btn_dim_x = ( XI_FU_MULTIPLE * fu_height ) / fu_width; + /* btn_dim_x is actual width of button */ +#if XIWS != XIWS_WM + /* make buttons 70% wide as high */ + btn_dim_x = ( int ) ( ( long ) btn_dim_x * 83L / 100L ); +#endif + btn_space = btn_dim_x / 6; + /* btn_dim_x2 is the button width + space, rounded up to the next even + * form unit */ + btn_dim_x2 = btn_dim_x + btn_space; + btn_dim_x2 = ( ( btn_dim_x2 + XI_FU_MULTIPLE ) / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + if ( !( field_data->xi_rct.top || field_data->xi_rct.bottom || + field_data->xi_rct.left || field_data->xi_rct.right ) ) + { + if ( field_data->button ) + { + int leading, + ascent, + descent, + font_height; + + XinWindowFontMap( itf_win, stxp->font ); + XinFontMetricsGet( stxp->font, &leading, &ascent, &descent ); + font_height = ascent + leading + descent; + edit_height = font_height + ( 2 * EDIT_BORDER_WIDTH_Y ) + + ( 2 * EDIT_BORDER_SPACE_Y ); + field_data->btn_rct.top = field_data->xi_pnt.v; + if ( field_data->button_on_left ) + { + field_data->btn_rct.left = field_data->xi_pnt.h; + field_data->btn_rct.right = + field_data->btn_rct.left + btn_dim_x; + } + else + { +#if XIWS == XIWS_WM + BOOLEAN b; + STX_DATA *stxp; + + stxp = ( STX_DATA * ) field_data->stx; + b = ( BOOLEAN ) ( stxp->attrib & XI_ATR_BORDER ); + field_data->btn_rct.left = stxp->rct.left + + field_data->field_width + ( b ? 24 : 8 ); + field_data->btn_rct.right = + field_data->btn_rct.left + 8; +#endif +#if XIWS != XIWS_WM + field_data->btn_rct.right = field_data->xi_pnt.h + + field_data->field_width + btn_dim_x2; + field_data->btn_rct.right = ( ( field_data->btn_rct.right + XI_FU_MULTIPLE ) + / XI_FU_MULTIPLE ) * XI_FU_MULTIPLE; + field_data->btn_rct.left = field_data->btn_rct.right + - btn_dim_x; +#endif + } + } + } + else + { + if ( field_data->button ) + { + field_data->btn_rct = field_data->xi_rct; + if ( field_data->button_on_left ) + { + field_data->btn_rct.right = + field_data->btn_rct.left + btn_dim_x2; + } + else + { + field_data->btn_rct.left = + field_data->btn_rct.right; + field_data->btn_rct.right += btn_dim_x2; + } + } + } + xi_fu_to_pu( xi_obj->itf, ( XinPoint * ) & field_data->btn_rct, 2 ); + field_data->btn_rct.bottom = field_data->btn_rct.top + + edit_height; + if ( field_data->xi_pnt.h || field_data->xi_pnt.v ) + { + field_data->rct.top = field_data->xi_pnt.v; + field_data->rct.left = field_data->xi_pnt.h; + field_data->rct.right = field_data->rct.left + + field_data->field_width; + field_data->rct.bottom = field_data->rct.top + + XI_FU_MULTIPLE; + } + else + field_data->rct = field_data->xi_rct; + xi_fu_to_pu( xi_obj->itf, ( XinPoint * ) & field_data->rct, 2 ); + break; + } + case XIT_BTN: + { + XI_BTN_DATA *btn_data; + + if ( xi_obj->parent->type != XIT_CONTAINER ) + { + btn_data = xi_obj->v.btn; + btn_data->rct = btn_data->xi_rct; + xi_fu_to_pu( xi_obj->itf, ( XinPoint * ) & btn_data->rct, 2 ); + } + break; + } + case XIT_CONTAINER: + { + XI_CONTAINER_DATA *container_data; + XinPoint p; + int i, + max_len, + len; + XI_OBJ *child; + XI_BTN_TYPE btn_type; + + container_data = xi_obj->v.container; + container_data->rct = container_data->xi_rct; + + xi_fu_to_pu( xi_obj->itf, ( XinPoint * ) & container_data->rct, 2 ); + p.v = container_data->btn_height; + p.h = container_data->btn_width; + xi_fu_to_pu( xi_obj->itf, &p, 1 ); + container_data->pix_height = p.v; + container_data->pix_width = p.h; + + max_len = 0; + for ( i = 0; i < xi_obj->nbr_children; ++i ) + { + child = xi_obj->children[i]; + if ( ( len = ( int ) strlen( child->v.btn->text ) ) > max_len ) + max_len = len; + } + btn_type = xi_obj->children[0]->v.btn->type; + xi_container_rect_calc( xi_obj, max_len, btn_type ); + for ( i = 0; i < xi_obj->nbr_children; ++i ) + xi_button_rect_calc( xi_obj->children[i], i ); + + break; + } + default: + break; + } + for ( i = 0; i < xi_obj->nbr_children; ++i ) + recalc_metrics( xi_obj->children[i] ); +} + + +void +xi_set_obj_font( XI_OBJ * xi_obj, XinFont * font ) +{ + switch ( xi_obj->type ) + { +case XIT_ITF: + { + XI_ITF_DATA *itf_data; + + itf_data = xi_obj->v.itf; + if ( itf_data->font ) + XinFontDestroy( itf_data->font ); + if ( font ) + XinFontCopy( &itf_data->font, font ); + else + itf_data->font = NULL; + + recalc_metrics( xi_obj ); + + xi_invalidate_rect( xi_get_window( xi_obj ), NULL ); + break; + } +case XIT_BTN: + { + XinRect rct; + + if ( xi_obj->v.btn->font != NULL ) + XinFontDestroy( xi_obj->v.btn->font ); + XinFontCopy( &xi_obj->v.btn->font, font ); + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_get_window( xi_obj->itf ), &rct ); + break; + } + case XIT_TEXT: + { + XinRect rct; + + if ( xi_obj->v.text->font != NULL ) + XinFontDestroy( xi_obj->v.text->font ); + XinFontCopy( &xi_obj->v.text->font, font ); + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_get_window( xi_obj->itf ), &rct ); + break; + } + case XIT_FIELD: + { + XinRect rct; + + stx_set_font( xi_obj->v.field->stx, font ); + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_get_window( xi_obj->itf ), &rct ); + break; + } + case XIT_COLUMN: + { + XI_OBJ *list; + + list = xi_obj->parent; + lm_set_font( list->v.list->lm, LM_COLUMN, xi_obj_to_idx( xi_obj ), + 0, font ); + break; + } + case XIT_CELL: + if ( !xi_obj->v.cell.is_vert_scrolled ) + { + XI_OBJ *list; + XinRect rct; + + list = xi_obj->parent; + lm_set_font( list->v.list->lm, LM_CELL, xi_obj->v.cell.row, + xi_obj->v.cell.column, font ); + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_get_window( xi_obj->itf ), &rct ); + } + break; + default: + break; + } +} + +void +xi_set_obj_font_id( XI_OBJ * xi_obj, void *font_id ) +{ +#ifdef XI_USE_XVT + XinFont *font = XinFontXvtConvert( font_id ); + + xi_set_obj_font( xi_obj, font ); + XinFontDestroy( font ); +#endif +} + +XI_CELL_SPEC * +xi_get_cell_selection( XI_OBJ * list, int *nbr_cellsp ) +{ + int r, + c, + nbr_rows, + nbr_columns, + nbr_cells, + cnt; + XI_OBJ cell_obj, + row_obj; + XI_LIST_DATA *list_data; + XI_OBJ **members; + int nbr_members; + + members = xi_get_member_list( list, &nbr_members ); + xi_get_list_info( list, &nbr_rows ); + nbr_columns = list->nbr_children; + nbr_cells = 0; + for ( r = 0; r < nbr_rows; ++r ) + for ( c = 0; c < nbr_columns; ++c ) + { + XI_MAKE_CELL( &cell_obj, list, ( unsigned char ) r, ( unsigned char ) c ); + XI_MAKE_ROW( &row_obj, list, ( unsigned char ) r ); + if ( ( xi_get_attrib( &cell_obj ) & XI_ATR_SELECTED ) || + ( xi_get_attrib( members[c] ) & XI_ATR_SELECTED ) || + ( xi_get_attrib( &row_obj ) & XI_ATR_SELECTED ) ) + ++nbr_cells; + } + *nbr_cellsp = nbr_cells; + list_data = list->v.list; + if ( list_data->cell_spec ) + list_data->cell_spec = ( XI_CELL_SPEC * ) xi_tree_realloc( list_data->cell_spec, + ( size_t ) nbr_cells * sizeof( XI_CELL_SPEC ) ); + else + list_data->cell_spec = ( XI_CELL_SPEC * ) xi_tree_malloc( + ( size_t ) nbr_cells * sizeof( XI_CELL_SPEC ), list_data ); + cnt = 0; + for ( r = 0; r < nbr_rows; ++r ) + for ( c = 0; c < nbr_columns; ++c ) + { + XI_MAKE_CELL( &cell_obj, list, ( unsigned char ) r, ( unsigned char ) c ); + XI_MAKE_ROW( &row_obj, list, ( unsigned char ) r ); + if ( ( xi_get_attrib( &cell_obj ) & XI_ATR_SELECTED ) || + ( xi_get_attrib( members[c] ) & XI_ATR_SELECTED ) || + ( xi_get_attrib( &row_obj ) & XI_ATR_SELECTED ) ) + { + list_data->cell_spec[cnt].row = r; + list_data->cell_spec[cnt].column = c; + ++cnt; + } + } + return list_data->cell_spec; +} + +BOOLEAN +xi_is_checked( XI_OBJ * xi_obj ) +{ + BOOLEAN retval = FALSE; + + if ( xi_obj->type == XIT_BTN ) + retval = xi_obj->v.btn->checked; + return retval; +} + +void +xi_check( XI_OBJ * xi_obj, BOOLEAN check ) +{ + XinWindow win; + static BOOLEAN inside = FALSE; + XI_BTN_DATA *btn; + + if ( check != 0 && check != 1 ) + check = 1; + if ( !xi_get_native_controls( xi_obj ) ) + if ( xi_is_checked( xi_obj ) == check ) + return; + win = xi_obj->itf->v.itf->xin_win; + btn = xi_obj->v.btn; + xi_obj->v.btn->checked = check; + if ( !xi_get_native_controls( xi_obj ) ) + { + switch ( btn->type ) + { + case XIBT_BUTTON: + xi_invalidate_rect( win, &btn->rct ); + break; + case XIBT_BUTTON_CHECKBOX: + case XIBT_BUTTON_RADIOBTN: + case XIBT_RADIOBTN: + case XIBT_CHECKBOX: + case XIBT_TABBTN: + { + BOOLEAN enabled, + visible, + focus; + unsigned long attrib; + + attrib = xi_get_attrib( xi_obj ); + enabled = ( ( attrib & XI_ATR_ENABLED ) != 0 ); + visible = ( ( attrib & XI_ATR_VISIBLE ) != 0 ); + focus = ( xi_get_focus( xi_obj->itf ) == xi_obj ); + if ( btn->drawable || ( btn->type == XIBT_TABBTN && !check ) ) + { + XinRect temp = btn->rct; + if ( btn->type == XIBT_TABBTN ) + temp.bottom++; + xi_invalidate_rect( win, &temp ); + } else + xi_draw_button( xi_obj, &btn->rct, enabled, visible, focus, + btn->down, btn->dflt, btn->checked, TRUE, FALSE ); + break; + } + } + } +#ifdef XI_USE_XVT + else + { + switch ( btn->type ) + { + case XIBT_CHECKBOX: + XinWindowCheckBox( btn->btnctl, check ); + break; + case XIBT_RADIOBTN: + case XIBT_TABBTN: + { + XinWindow wins[MAX_RADIO_BUTTONS]; + //XI_BTN_TYPE type; + XI_OBJ *parent; + + //type = xi_obj->v.btn->type; + parent = xi_obj->parent; + if ( parent->type == XIT_CONTAINER /* && + ( type == XIBT_RADIOBTN || type == XIBT_TABBTN ) */) + { + if (check) + { + int i; + + if ( parent->nbr_children > MAX_RADIO_BUTTONS ) + XinError( 20089, XinSeverityFatal, 0L ); + for ( i = 0; i < parent->nbr_children; ++i ) + wins[i] = parent->children[i]->v.btn->btnctl; + XinWindowCheckRadioButton( btn->btnctl, wins, + parent->nbr_children ); + } + //return; + } + else + { + XinWindowCheckBox( btn->btnctl, check ); + return; + } + break; + } + default: + break; + } + } +#endif + if ( !inside && xi_obj->parent->type == XIT_CONTAINER && + ( xi_obj->v.btn->type == XIBT_RADIOBTN || + xi_obj->v.btn->type == XIBT_TABBTN || + xi_obj->v.btn->type == XIBT_BUTTON_RADIOBTN ) ) + { + XI_OBJ **child; + XI_OBJ *parent; + int i; + + inside = TRUE; + parent = xi_obj->parent; + child = parent->children; + for ( i = 0, child = parent->children; i < parent->nbr_children; + ++i, ++child ) + if ( *child != xi_obj ) + if ( xi_is_checked( *child ) ) + xi_check( *child, FALSE ); + inside = FALSE; + } +} + +int +xi_obj_to_idx( XI_OBJ * xi_obj ) +{ + int column_idx; + XI_OBJ **objp; + int n; + + n = xi_obj->parent->nbr_children; + objp = xi_obj->parent->children; + for ( column_idx = 0; column_idx < n; objp++, ++column_idx ) + { + if ( ( *objp ) == xi_obj ) + break; + } + return column_idx; +} + + +void +xi_set_update_obj( XI_OBJ * xi_obj ) +{ + /* Check to be sure that the object is visible */ + if ( xi_obj != NULL ) + { + + XinRect obj_r; + XinRect client_r; + XI_OBJ *itf; + + itf = xi_obj->itf; + xi_get_rect( xi_obj, &obj_r ); + XinWindowRectGet( itf->v.itf->xin_win, &client_r ); + XinRectIntersect( &obj_r, &obj_r, &client_r ); + if ( XinRectEmpty( &obj_r ) ) + xi_obj = NULL; + + itf->v.itf->update_obj = xi_obj; + } +} + + +int +xi_get_visible_rows( XI_OBJ * xi_obj, int *first_vis, int *last_vis ) +{ + return lm_get_visible_rows( xi_obj->v.list->lm, first_vis, last_vis ); +} + + +void +xi_set_row_height( XI_OBJ * xi_obj, int height ) +{ + XI_OBJ *list; + + list = xi_obj->parent; + lm_set_row_height( list->v.list->lm, xi_obj->v.row, height, TRUE, 0, FALSE ); +} + + +#if 0 +long +xi_long_time( void ) +{ +#if XVT_OS == XVT_OS_DOS + struct time t; + long l; + + gettime( &t ); + l = t.ti_hund + + t.ti_sec * 100 + + t.ti_min * 6000 + + t.ti_hour * 360000L; + return l; +#endif +} + +#endif + + +void +xi_set_color( XI_OBJ * xi_obj, XI_COLOR_PART part, XinColor color ) +{ + XinRect rct; + BOOLEAN changed; + + changed = FALSE; + switch ( xi_obj->type ) + { + case XIT_FIELD: + { + STX_DATA *stxp; + + stxp = ( STX_DATA * ) xi_obj->v.field->stx; + switch ( part ) + { + case XIC_ENABLED: + changed = ( stxp->enabled_color != color ); + stxp->enabled_color = color; + break; + case XIC_BACK: + changed = ( stxp->back_color != color ); + stxp->back_color = color; + break; + case XIC_HILIGHT: + changed = ( stxp->hilight_color != color ); + stxp->hilight_color = color; + break; + case XIC_ACTIVE: + changed = ( stxp->active_color != color ); + stxp->active_color = color; + break; + case XIC_ACTIVE_BACK: + changed = ( stxp->active_back_color != color ); + stxp->active_back_color = color; + break; + case XIC_SHADOW: + changed = ( stxp->shadow_color != color ); + stxp->shadow_color = color; + break; + case XIC_DISABLED: + changed = ( stxp->disabled_color != color ); + stxp->disabled_color = color; + break; + case XIC_DISABLED_BACK: + changed = ( stxp->disabled_back_color != color ); + stxp->disabled_back_color = color; + break; + default: + break; + } + if ( changed ) + stx_update_colors( xi_obj->v.field->stx ); + break; + } + case XIT_CELL: + if ( !xi_obj->v.cell.is_vert_scrolled ) + { + LM_CELL_DATA *cell_data; + XI_OBJ *list_obj; + LM_DATA *lmp; + int row = xi_obj->v.cell.row; + int col = xi_obj->v.cell.column; + + list_obj = xi_obj->parent; + lmp = ( LM_DATA * ) list_obj->v.list->lm; + cell_data = &lmp->cell_data[row][col]; + switch ( part ) + { + case XIC_ENABLED: + changed = ( cell_data->color != color ); + cell_data->color = color; + break; + case XIC_BACK: + changed = ( cell_data->back_color != color ); + cell_data->back_color = color; + break; + default: + break; + } + } + break; + case XIT_ROW: + if ( part == XIC_ENABLED ) + lm_set_color( xi_obj->parent->v.list->lm, LM_ROW, xi_obj->v.row, + 0, FALSE, color, FALSE ); + changed = TRUE; + break; + case XIT_TEXT: + { + XI_TEXT_DATA *xi_td; + + xi_td = ( XI_TEXT_DATA * ) xi_obj->v.text; + switch ( part ) + { + case XIC_FORE: + case XIC_ENABLED: + changed = ( xi_td->fore_color != color ); + xi_td->fore_color = color; + break; + case XIC_BACK: + changed = ( xi_td->back_color != color ); + xi_td->back_color = color; + break; + default: + break; + } + break; + } + case XIT_LINE: + { + XI_LINE_DATA *xi_ld; + + xi_ld = ( XI_LINE_DATA * ) xi_obj->v.line; + switch ( part ) + { + case XIC_FORE: + case XIC_ENABLED: + changed = ( xi_ld->fore_color != color ); + xi_ld->fore_color = color; + break; + case XIC_BACK: + changed = ( xi_ld->back_color != color ); + xi_ld->back_color = color; + break; + default: + break; + } + break; + } + case XIT_RECT: + { + XI_RECT_DATA *xi_rd; + + xi_rd = ( XI_RECT_DATA * ) xi_obj->v.rect; + switch ( part ) + { + case XIC_FORE: + case XIC_ENABLED: + changed = ( xi_rd->fore_color != color ); + xi_rd->fore_color = color; + break; + case XIC_BACK: + changed = ( xi_rd->back_color != color ); + xi_rd->back_color = color; + break; + case XIC_HILIGHT: + changed = ( xi_rd->hilight_color != color ); + xi_rd->hilight_color = color; + break; + case XIC_SHADOW: + changed = ( xi_rd->shadow_color != color ); + xi_rd->shadow_color = color; + break; + default: + break; + } + break; + } + case XIT_ITF: + { + XI_ITF_DATA *xi_id; + + xi_id = ( XI_ITF_DATA * ) xi_obj->v.itf; + if ( part == XIC_BACK ) + changed = ( xi_id->back_color != color ); + xi_id->back_color = color; + break; + } + case XIT_LIST: + { + LM_DATA *lmp; + + lmp = ( LM_DATA * ) xi_obj->v.list->lm; + switch ( part ) + { + case XIC_ENABLED: + changed = ( lmp->enabled_color != color ); + lmp->enabled_color = color; + break; + case XIC_BACK: + changed = ( lmp->back_color != color ); + lmp->back_color = color; + break; + case XIC_ACTIVE: + changed = ( lmp->active_color != color ); + lmp->active_color = color; + break; + case XIC_ACTIVE_BACK: + changed = ( lmp->active_back_color != color ); + lmp->active_back_color = color; + break; + case XIC_DISABLED: + changed = ( lmp->disabled_color != color ); + lmp->disabled_color = color; + break; + case XIC_DISABLED_BACK: + changed = ( lmp->disabled_back_color != color ); + lmp->disabled_back_color = color; + break; + case XIC_WHITE_SPACE: + changed = ( lmp->white_space_color != color ); + lmp->white_space_color = color; + break; + default: + break; + } + break; + } + default: + break; + } + + if ( changed ) + { + if ( xi_obj->type == XIT_ITF ) + { + xi_get_rect( xi_obj, &rct ); + xi_invalidate_rect( xi_get_window( xi_obj->itf ), &rct ); + } + else if ( ( xi_get_attrib( xi_obj ) & XI_ATR_VISIBLE ) != 0 ) + { + xi_get_rect( xi_obj, &rct ); + + /* Returned rectangle does not cause an update for a line. Adjust the + * coordinates so it does. */ + if ( xi_obj->type == XIT_LINE ) + { + rct.top = rct.top - 1; + rct.bottom = rct.bottom + 1; + } + xi_invalidate_rect( xi_get_window( xi_obj->itf ), &rct ); + } + } +} + + +void +xi_cell_request( XI_OBJ * xi_obj ) +{ + switch ( xi_obj->type ) + { + case XIT_LIST: + lm_cell_request( xi_obj->v.list->lm, LM_LIST, 0, 0 ); + break; + case XIT_COLUMN: + lm_cell_request( xi_obj->parent->v.list->lm, LM_COLUMN, xi_obj_to_idx( xi_obj ), 0 ); + break; + case XIT_ROW: + lm_cell_request( xi_obj->parent->v.list->lm, LM_ROW, xi_obj->v.row, 0 ); + break; + case XIT_CELL: + if ( !xi_obj->v.cell.is_vert_scrolled ) + lm_cell_request( xi_obj->parent->v.list->lm, LM_CELL, xi_obj->v.cell.row, + xi_obj->v.cell.column ); + break; + default: + break; + } +} + + +void +xi_get_visible_columns( XI_OBJ * xi_obj, int *first_vis, int *last_vis ) +{ + lm_get_visible_columns( xi_obj->v.list->lm, first_vis, last_vis ); +} + + +void +xi_set_list_size( XI_OBJ * xi_obj, int height, int width ) +{ + lm_set_list_size( xi_obj->v.list->lm, height, width ); +} + +/*--------------------------------------------------------------------- +function: xi_container_rect_calc +cnt_obj: container object +max_text_len: longest button text (only used for XI_STACK_HORIZONTAL) +btn_type type of buttons in container +process: Calculate the container size & button positioning parameters +---------------------------------------------------------------------*/ +static void +calc_horizontal_stack( XI_OBJ * itf, XI_CONTAINER_DATA * container, + XI_BTN_TYPE btn_type, int max_text_len ) +{ + int btn_width, + max_width, + horz_spacing, + btn_height = 0; + long horz_form_unit; + long vert_form_unit; + BOOLEAN center = FALSE; + XinRect container_rect; + + container_rect = container->rct; + btn_width = max_text_len; +#if XIWS == XIWS_MAC + btn_width *= ( XI_FU_MULTIPLE + 2 ); +#elif XIWS == XIWS_WIN + if ( xi_get_pref( XI_PREF_NATIVE_CTRLS ) ) + btn_width *= ( XI_FU_MULTIPLE + 2 ); + else + btn_width *= XI_FU_MULTIPLE; +#else + btn_width *= XI_FU_MULTIPLE; +#endif + horz_form_unit = xi_get_fu_width( itf ); + vert_form_unit = xi_get_fu_height( itf ); + btn_width += ( int ) xi_get_pref( XI_PREF_BUTTON_PAD ); +#if 0 + /* old tabs */ + if ( btn_type == XIBT_TABBTN ) + btn_width += ( int ) xi_get_pref( XI_PREF_BUTTON_PAD ) / 2; +#endif + /* convert to pixels */ + btn_width = ( int ) ( ( btn_width * horz_form_unit ) / XI_FU_MULTIPLE ); + if ( container->packed || btn_type == XIBT_TABBTN ) + horz_spacing = 0; + else if ( ( horz_spacing = ( int ) xi_get_pref( XI_PREF_HORZ_PIXEL_SPACING ) ) + == 0 ) + horz_spacing = ( short ) ( ( xi_get_pref( XI_PREF_HORZ_SPACING ) + * horz_form_unit ) / XI_FU_MULTIPLE ); + + /* If pix_width is larger, use it */ + if ( container->pix_width > btn_width ) + btn_width = container->pix_width; + + /* figure out if maximum width is too wide, and if so, truncate */ + max_width = ( ( container_rect.right - container_rect.left ) - + ( container->nbr_buttons - 1 ) * horz_spacing ) / container->nbr_buttons; + if ( btn_width > max_width ) + btn_width = max_width; + switch ( btn_type ) + { + case XIBT_BUTTON: + case XIBT_BUTTON_CHECKBOX: + case XIBT_BUTTON_RADIOBTN: + if ( container->pix_height ) + btn_height = container->pix_height; + else + btn_height = ( int ) ( ( xi_get_pref( XI_PREF_BUTTON_HEIGHT ) * vert_form_unit ) + / XI_FU_MULTIPLE ); + center = TRUE; + break; + case XIBT_TABBTN: + btn_height = container_rect.bottom - container_rect.top; + center = FALSE; + break; + case XIBT_CHECKBOX: + case XIBT_RADIOBTN: + btn_height = ( int ) vert_form_unit; + center = TRUE; + break; + } + if ( center == TRUE ) + { + container_rect.top += ( container_rect.bottom - container_rect.top + - btn_height ) / 2; + container_rect.bottom = container_rect.top + btn_height; + } + container->rct = container_rect; + container->nbr_across = container->nbr_buttons; + container->nbr_down = 1; + container->pix_width = btn_width; + container->pix_height = btn_height; + container->step_across = btn_width + horz_spacing; + container->step_down = 0; +} + +static void +calc_vertical_stack( XI_OBJ * itf, XI_CONTAINER_DATA * container, + XI_BTN_TYPE btn_type ) +{ + int btn_height, + max_height, + top_ofst = 0, + vert_spacing = 0; + XinRect container_rect; + long vert_form_unit; + + vert_form_unit = xi_get_fu_height( itf ); + container_rect = container->rct; + switch ( btn_type ) + { + case XIBT_BUTTON: + case XIBT_BUTTON_CHECKBOX: + case XIBT_BUTTON_RADIOBTN: + case XIBT_TABBTN: + if ( container->packed ) + vert_spacing = 0; + else if ( ( vert_spacing = ( int ) xi_get_pref( XI_PREF_VERT_PIXEL_SPACING ) ) + == 0 ) + vert_spacing = ( int ) ( ( xi_get_pref( XI_PREF_VERT_SPACING ) + * vert_form_unit ) / XI_FU_MULTIPLE ); + top_ofst = vert_spacing / 2; + break; + case XIBT_CHECKBOX: + case XIBT_RADIOBTN: + vert_spacing = 0; + top_ofst = 0; + break; + default: + break; + } + if ( container->pix_height ) + btn_height = container->pix_height; + else + btn_height = ( int ) ( ( xi_get_pref( XI_PREF_BUTTON_HEIGHT ) * vert_form_unit ) + / XI_FU_MULTIPLE ); + max_height = ( container_rect.bottom - container_rect.top - top_ofst + - ( ( container->nbr_buttons - 1 ) * vert_spacing ) ) / container->nbr_buttons; + switch ( btn_type ) + { + case XIBT_CHECKBOX: + case XIBT_RADIOBTN: + btn_height = ( int ) vert_form_unit; + break; + default: + break; + } + if ( btn_height > max_height ) + btn_height = max_height; + if ( btn_height < vert_form_unit ) + XinError( 20014, XinSeverityFatal, 0L ); + container_rect.top += top_ofst; + container->rct = container_rect; + container->nbr_across = 1; + container->nbr_down = container->nbr_buttons; + if ( container->pix_width == 0 ) + container->pix_width = container->rct.right - container->rct.left; + container->pix_height = btn_height; + container->step_across = 0; + container->step_down = btn_height + vert_spacing; +} + +static void +calc_grid( XI_OBJ * itf, XI_CONTAINER_DATA * container ) +{ + int hz_pix_space, + vt_pix_space, + slack; + XinPoint pnt; + XinRect container_rect; + + container_rect = container->rct; + if ( !( ( container->btn_width > 0 ) || ( container->btn_height > 0 ) ) ) + XinError( 30208, XinSeverityFatal, 0L ); + if ( container->pix_height == 0 || container->pix_width == 0 ) + { + pnt.v = container->btn_height; + pnt.h = container->btn_width; + xi_fu_to_pu( itf, &pnt, 1 ); + if ( ( pnt.v == 0 ) || ( pnt.h == 0 ) ) + { + /* make it so that pnt.h and pnt.v are the same */ + if ( pnt.v == 0 ) + pnt.v = pnt.h; + if ( pnt.h == 0 ) + pnt.h = pnt.v; + } + container->pix_height = pnt.v; + container->pix_width = pnt.h; + } + if ( container->pix_height > container_rect.bottom - container_rect.top ) + XinError( 20032, XinSeverityFatal, 0L ); + if ( container->pix_width > container_rect.right - container_rect.left ) + XinError( 20033, XinSeverityFatal, 0L ); + pnt.v = XI_FU_MULTIPLE; + xi_fu_to_pu( itf, &pnt, 1 ); + if ( ( container->pix_height < pnt.v ) ) + XinError( 20034, XinSeverityFatal, 0L ); + if ( container->packed == TRUE ) + { + /* note that if not native, the space is NEGATIVE */ + vt_pix_space = ( ( BOOLEAN ) xi_get_pref( XI_PREF_NATIVE_CTRLS ) ) + ? 0 : -( int ) xi_get_pref( XI_PREF_CONTAINER_GRID_WIDTH ); + hz_pix_space = vt_pix_space; + } + else + { + pnt.v = ( int ) xi_get_pref( XI_PREF_VERT_SPACING ); + pnt.h = ( int ) xi_get_pref( XI_PREF_HORZ_SPACING ); + xi_fu_to_pu( itf, &pnt, 1 ); + vt_pix_space = pnt.v; + hz_pix_space = pnt.h; + } + container->step_down = container->pix_height + vt_pix_space; + container->step_across = container->pix_width + hz_pix_space; + if ( container->orientation == XI_GRID_HORIZONTAL ) + { + container->nbr_across = ( container_rect.right - container_rect.left + + hz_pix_space ) / container->step_across; + container->nbr_down = 1 + ( container->nbr_buttons - 1 ) + / container->nbr_across; + slack = ( container_rect.bottom - container_rect.top + vt_pix_space ) + - ( container->nbr_down * container->step_down ); + } + else + { + container->nbr_down = ( container_rect.bottom - container_rect.top + + vt_pix_space ) / container->step_down; + container->nbr_across = 1 + ( container->nbr_buttons - 1 ) + / container->nbr_down; + slack = ( container_rect.right - container_rect.left + hz_pix_space ) + - ( container->nbr_across * container->step_across ); + } + if ( slack < 0 ) + XinError( 20035, XinSeverityFatal, 0L ); +} + +void +xi_container_rect_calc( XI_OBJ * cnt_obj, int max_text_len, + XI_BTN_TYPE btn_type ) +{ + XI_CONTAINER_DATA *container; + + container = cnt_obj->v.container; + if ( container->rct.left == 0 && container->rct.top == 0 + && container->rct.bottom == 0 && container->rct.right == 0 ) + { + XinRect rect; + + rect = container->xi_rct; + xi_fu_to_pu( cnt_obj->itf, ( XinPoint * ) & rect, 2 ); + container->rct = rect; + } + switch ( container->orientation ) + { + case XI_STACK_HORIZONTAL: + calc_horizontal_stack( cnt_obj->itf, container, btn_type, max_text_len ); + break; + case XI_STACK_VERTICAL: + calc_vertical_stack( cnt_obj->itf, container, btn_type ); + break; + case XI_GRID_HORIZONTAL: + case XI_GRID_VERTICAL: + calc_grid( cnt_obj->itf, container ); + break; + } +} + +/*--------------------------------------------------------------------- +function: xi_button_rect_calc +btn_obj: Button object (with data structure complete except for rct) +sequence: button sequence within parent (used for contained buttons only) +process: Calculate the button rectangle size, either from the + container information or the xi rectangle. +---------------------------------------------------------------------*/ +void +xi_button_rect_calc( XI_OBJ * btn_obj, int sequence ) +{ + XinRect rct; + BOOLEAN packed = FALSE; /* button has no dflt or focus rects */ + + if ( btn_obj->parent->type == XIT_CONTAINER ) + { + int row, + col; + XI_CONTAINER_DATA *cdata; + + cdata = btn_obj->parent->v.container; + switch ( cdata->orientation ) + { + case XI_STACK_HORIZONTAL: + row = 0; + col = sequence; + packed = FALSE; + break; + case XI_STACK_VERTICAL: + row = sequence; + col = 0; + packed = FALSE; + break; + case XI_GRID_HORIZONTAL: + row = sequence / cdata->nbr_across; + col = sequence - row * cdata->nbr_across; + packed = cdata->packed; + break; + case XI_GRID_VERTICAL: + col = sequence / cdata->nbr_down; + row = sequence - col * cdata->nbr_down; + packed = cdata->packed; + break; + default: + row = col = 0; + break; + + } + rct.top = cdata->rct.top + row * cdata->step_down; + rct.left = cdata->rct.left + col * cdata->step_across; + rct.bottom = rct.top + cdata->pix_height; + rct.right = rct.left + cdata->pix_width; + } + else + { + rct = btn_obj->v.btn->rct; + if ( rct.left == 0 && rct.top == 0 && rct.bottom == 0 && rct.right == 0 ) + { + rct = btn_obj->v.btn->xi_rct; + xi_fu_to_pu( btn_obj->itf, ( XinPoint * ) & rct, 2 ); + } + if ( rct.top == rct.bottom ) + { + /* use default height */ + rct.bottom = rct.top + ( int ) xi_get_pref( XI_PREF_BUTTON_HEIGHT ); + } + packed = FALSE; + } + btn_obj->v.btn->rct = rct; + btn_obj->v.btn->packed = packed; +} + +/*--------------------------------------------------------------------- +function: xi_container_reorient +cnt_obj: The EXISTING container object +cnt_def: A revised definition of the container: + XI_RCT xi_rct; new rectangle, if empty, use old + XI_CONTAINER_ORIENTATION orientation; new value + int tab_cid; NOT USED + short btn_width; for grids, new value in form units + short btn_height; for grids, new value in form units + BOOLEAN packed; new value +process: change the container position, orientation, etc. +---------------------------------------------------------------------*/ +void +xi_container_reorient( XI_OBJ * cnt_obj, XI_CONTAINER_DEF * cnt_def ) +{ + int i, + len, + max_len; + XI_CONTAINER_DATA *cdata; + + if ( cnt_obj->type != XIT_CONTAINER ) + XinError( 20036, XinSeverityFatal, 0L ); + cdata = cnt_obj->v.container; + xi_invalidate_rect( xi_get_window( cnt_obj->itf ), &cdata->rct ); + if ( ( cnt_def->xi_rct.bottom > cnt_def->xi_rct.top ) + || ( cnt_def->xi_rct.right > cnt_def->xi_rct.left ) ) + cdata->xi_rct = cnt_def->xi_rct; + cdata->rct = cnt_def->pixel_rect; + cdata->orientation = cnt_def->orientation; + cdata->btn_height = cnt_def->btn_height; + cdata->btn_width = cnt_def->btn_width; + cdata->packed = cnt_def->packed; + max_len = 0; + for ( i = 0; i < cnt_obj->nbr_children; ++i ) + { + if ( ( len = ( int ) strlen( cnt_obj->children[i]->v.btn->text ) ) > max_len ) + max_len = len; + } + xi_container_rect_calc( cnt_obj, max_len, cnt_obj->children[0]->v.btn->type ); + for ( i = 0; i < cnt_obj->nbr_children; ++i ) + { + xi_button_rect_calc( cnt_obj->children[i], i ); + } + xi_invalidate_rect( xi_get_window( cnt_obj->itf ), &cdata->rct ); +} + +/*--------------------------------------------------------------------------*/ +/* xi_def_get_font */ +/*--------------------------------------------------------------------------*/ + +XinFont * +xi_def_get_font( XI_OBJ_DEF * obj_def ) +{ + XinFont *font = NULL; + + if ( !obj_def ) + { + XinFontCopy( &font, xi_get_system_font( ) ); + return font; + } + switch ( obj_def->type ) + { + case XIT_FIELD: + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &font, obj_def->v.field->font ); + } +#ifdef XI_USE_XVT + else + { + if ( obj_def->v.field->font_id != NULL ) + font = XinFontXvtConvert( obj_def->v.field->font_id ); + } +#endif + break; + case XIT_TEXT: + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &font, obj_def->v.text->font ); + } +#ifdef XI_USE_XVT + else + { + if ( obj_def->v.text->font_id != NULL ) + font = XinFontXvtConvert( obj_def->v.text->font_id ); + } +#endif + break; + case XIT_LIST: + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &font, obj_def->v.list->font ); + } +#ifdef XI_USE_XVT + else + { + if ( obj_def->v.list->font_id != NULL ) + font = XinFontXvtConvert( obj_def->v.list->font_id ); + } +#endif + break; + case XIT_ITF: + if ( ( BOOLEAN ) xi_get_pref( XI_PREF_R4_API ) ) + { + XinFontCopy( &font, obj_def->v.itf->font ); + } +#ifdef XI_USE_XVT + else + { + if ( obj_def->v.itf->font_id != NULL ) + font = XinFontXvtConvert( obj_def->v.itf->font_id ); + } +#endif + break; + default: + break; + } + if ( font != NULL ) + return font; + return xi_def_get_font( obj_def->parent ); +} + +/*--------------------------------------------------------------------------*/ +/* xi_get_xil_pref */ +/*--------------------------------------------------------------------------*/ + +BOOLEAN +xi_get_xil_pref( XI_OBJ * obj ) +{ + assert( obj->type == XIT_ITF ); + if ( obj->v.itf->use_xil_win ) + return TRUE; + return ( BOOLEAN ) xi_get_pref( XI_PREF_XIL ); +} + + +BOOLEAN +xi_def_get_xil_pref( XI_OBJ_DEF * obj_def ) +{ + if ( obj_def != 0 ) + { + assert( obj_def->type == XIT_ITF ); + if ( obj_def->v.itf->use_xil_win ) + return TRUE; + } + return ( BOOLEAN ) xi_get_pref( XI_PREF_XIL ); +} + + +BOOLEAN +xi_pt_in_rect( XinRect * rct, XinPoint pnt ) +{ + return ( pnt.h >= rct->left && + pnt.h < rct->right && + pnt.v >= rct->top && + pnt.v < rct->bottom ); +} + +void +xi_draw_text( XinWindow win, XinFont * font, int x, int y, char *string, int len ) +{ + xi_set_cur_window( win ); + x -= cur_delta_x; + y -= cur_delta_y; +#if XIWS == XIWS_WM + y -= 8; + { + DRAW_CTOOLS ct; + + XinWindowDrawToolsGet( win, &ct ); + if ( ct.mode == M_XOR ) + XinWindowDrawModeSet( win, M_COPY ); + } +#endif + XinWindowTextDraw( win, font, x, y, string, len ); +} + + +void +xi_caret_on( XinWindow win, int x, int y, int height, XinRect * clip_rect ) +{ + XI_ITF_DATA *itf_data; + XinPoint p; + XinRect local_clip; + XinDrawTools dt; + + itf_data = xi_get_itf( win )->v.itf; +#ifdef XI_USE_TX_SUPPORT + if ( itf_data->caret_is_on ) + { + XinWindowCaretOff( win ); + } +#endif + itf_data->caret_x = x; + itf_data->caret_y = y; + itf_data->caret_height = height; + itf_data->caret_is_on = TRUE; + itf_data->caret_clip = *clip_rect; + p.h = x; + p.v = y; + vpnt_to_ppnt( win, &p ); + x = p.h; + y = p.v; + local_clip = *clip_rect; + vrct_to_prct( win, &local_clip ); + XinWindowDrawToolsGet( win, &dt ); + XinWindowCaretOn( win, x, y, height, dt.text_back_color, &local_clip ); +} + +void +xi_set_clip( XinWindow win, XinRect * rctp ) +{ + XinRect r; + + if ( rctp ) + { + r = *rctp; + vrct_to_prct( win, &r ); + + if ( r.right <= r.left ) + r.right = r.left + 1; + if ( r.top > r.bottom ) + r.top = r.bottom; + XinWindowClipSet( win, &r ); + } + else + XinWindowClipSet( win, NULL ); +} + +char * +xi_get_text_string( char *src, unsigned long attrib ) +{ + static char buf[256] = { 0 }; + + int len = strlen( src ); + len = min( len, sizeof( buf ) - 1 ); + if ( attrib & XI_ATR_PASSWORD ) + memset( buf, ( char ) xi_get_pref( XI_PREF_PASSWORD_CHAR ), len ); + else + gstrncpy( buf, src, len ); + + buf[len] = '\0'; + return buf; +} + +BOOLEAN +xi_cr_is_ok( XI_OBJ * xi_obj ) +{ + if ( xi_obj == NULL ) + return FALSE; + switch ( xi_obj->type ) + { + case XIT_FIELD: + return stx_cr_is_ok( xi_obj->v.field->stx ); + case XIT_CELL: + return lm_cr_is_ok( xi_obj->parent->v.list->lm, xi_obj->v.cell.row, xi_obj->v.cell.column, + xi_obj->v.cell.is_vert_scrolled ); + case XIT_BTN: + return TRUE; + default: + return FALSE; + } +} + +void +xi_draw_dotted_rect( XinWindow win, XinRect * rctp ) +{ +/* Commented by Guy: do not remove + XinPoint p1, + p2, + p3, + p4; + + p1.v = rctp->top + 1; + for ( p1.h = rctp->left + 1; p1.h < rctp->right - 1; p1.h += 2 ) + { + p2 = p1; + ++p2.h; + xi_move_to( win, p1 ); + xi_draw_line( win, p2 ); + p3 = p1; + p3.v = rctp->bottom - 1; + p4 = p3; + ++p4.h; + xi_move_to( win, p3 ); + xi_draw_line( win, p4 ); + } + p1.h = rctp->left; + for ( p1.v = rctp->top + 2; p1.v < rctp->bottom - 1; p1.v += 2 ) + { + p2 = p1; + ++p2.v; + xi_move_to( win, p1 ); + xi_draw_line( win, p2 ); + p3 = p1; + p3.h = rctp->right - 1; + p4 = p3; + ++p4.v; + xi_move_to( win, p3 ); + xi_draw_line( win, p4 ); + } +*/ + XinWindowDottedRectDraw(win, rctp); +} + +BOOLEAN +xi_focus_obj_is_cell_button( XI_OBJ * focus_obj ) +{ + if ( focus_obj->type != XIT_CELL ) + return FALSE; + return lm_is_button_full_cell( focus_obj->parent->v.list->lm, focus_obj->v.cell.row, + focus_obj->v.cell.column ); +} + +void +xi_draw_foc_and_dflt_if_necessary( XI_OBJ * focus_obj, XI_OBJ * next_obj ) +{ + int focus_obj_cr_ok, + next_obj_cr_ok; + + focus_obj_cr_ok = xi_cr_is_ok( focus_obj ); + next_obj_cr_ok = xi_cr_is_ok( next_obj ); + if ( focus_obj_cr_ok != next_obj_cr_ok ) + xi_draw_foc_and_dflt( focus_obj->itf ); +} + +BOOLEAN +xi_get_native_controls( XI_OBJ * obj ) +{ + if ( obj != NULL && obj->type == XIT_BTN ) + { + switch ( obj->v.btn->draw_as ) + { + case XIBT_EMULATED: + return FALSE; + case XIBT_NATIVE: + return TRUE; + default: + break; + } + } + return ( BOOLEAN ) xi_get_pref( XI_PREF_NATIVE_CTRLS ); +} + +#ifdef XI_USE_TX_SUPPORT +void +xi_caret_off( XinWindow win ) +{ + XI_ITF_DATA *itf_data; + + itf_data = xi_get_itf( win )->v.itf; + if ( itf_data->caret_is_on ) + { + itf_data->caret_is_on = FALSE; + XinWindowCaretOff( win ); + } +} + +#endif + +BOOLEAN +xi_get_obj_by_pointer( XI_OBJ * parent, XI_OBJ * target ) +{ + XI_OBJ **objlist; + int n; + + if ( parent == target ) + return ( TRUE ); + + switch ( parent->type ) + { + case XIT_GROUP: + case XIT_CELL: + case XIT_ROW: + return ( FALSE ); + default: + break; + } + + /* search in child list */ + objlist = xi_get_member_list( parent, &n ); + for ( ; n > 0; n--, objlist++ ) + { + /* call recursively for generality in future versions */ + if ( xi_get_obj_by_pointer( *objlist, target )) + return ( TRUE ); + } + return ( FALSE ); +} + +BOOLEAN +xi_is_obj( XI_OBJ* obj, XI_OBJ* itf ) +{ + /* + if (!xi_is_itf( itf )) + return FALSE; + return xi_get_obj_by_pointer( itf, obj ); + */ + return xi_is_itf(itf) && xi_get_obj_by_pointer(itf, obj); +} diff --git a/src/xi01/xiutils.h b/src/xi01/xiutils.h new file mode 100644 index 000000000..bdfa137b3 --- /dev/null +++ b/src/xi01/xiutils.h @@ -0,0 +1,133 @@ + +/******************************************************************************* +* Copyright 1991-1996 by ORCA Software, Inc. * +* * +* All rights reserved. May not be reproduced or distributed, in printed or * +* electronic form, without permission of ORCA Software, Inc. May not be * +* distributed as object code, separately or linked with other object modules, * +* without permission. * +*******************************************************************************/ + +#ifdef WIN32 +#if XIAGADLL == 1 + #define XIDLL __declspec(dllexport) +#else + #define XIDLL __declspec(dllimport) +#endif +#else +#define XIDLL +#endif + +extern XinBrush ltgray_cbrush; +extern XinBrush gray_cbrush; +extern XinBrush hollow_cbrush; +extern XinFont *xi_sysfont; +extern XinRect big_clip; + +/* DIMENSIONS FOR FIELD OBJET BORDER */ +#define XI_FLD_XBORDER XI_FU_MULTIPLE /* may change for OL implementation */ +#define XI_MULTILINE_SCROLLBAR_CID 31000 + +XIDLL XinRect *adjust_rect( XinRect * rct, int pwid ); +XIDLL int clip( int val, int mn, int mx ); +XIDLL void dbg_rct( char *tag, XinRect * rct ); +XIDLL void order_ints( int *ip1, int *ip2 ); + +/* +char* gstrncpy(char *dst, char *src, int n); +*/ + +XIDLL char *tstrncpy( char *dst, const char *src, int n ); +XIDLL void xi_adjust_sb_vir_itf( XinWindow win, XI_OBJ * itf ); +XIDLL void xi_button_rect_calc( XI_OBJ * btn_obj, int sequence ); +XIDLL void xi_container_rect_calc( XI_OBJ * cnt_obj, int max_text_len, + XI_BTN_TYPE btn_type ); +XIDLL XinFont *xi_def_get_font( XI_OBJ_DEF * obj_def ); +XIDLL BOOLEAN xi_get_xil_pref( XI_OBJ * obj ); +XIDLL void xi_draw_clipped_text( XinWindow win, XinFont * font, char *s, + XinRect * bound_rct, + XinRect * clip_rct, unsigned long attrib, + BOOLEAN set_the_cpen, int rule_and_space, + int len, char mnemonic, short mnemonic_instance, int *baseline ); +XIDLL void xi_dbg( char *buf ); +XIDLL void xi_draw_button( XI_OBJ * xi_obj, XinRect * rct, + BOOLEAN enabled, BOOLEAN visible, BOOLEAN focus, + BOOLEAN down, BOOLEAN dflt, BOOLEAN checked, BOOLEAN box_only, + BOOLEAN draw_border ); +XIDLL BOOLEAN xi_eh( XinWindow win, XinEvent * ep ); +XIDLL void xi_even_fu( int *f ); +XIDLL void xi_even_fu_pnt( XinPoint * p ); +XIDLL XinRect *xi_inflate_rect( XinRect * rct, int amount ); +XIDLL void xi_fu_to_pu_font( XinFont * font, XinPoint * pnt, int nbr_pnts ); +XIDLL XinRect *xi_get_enclosing_rect( XinRect * dst, XinRect * src1, XinRect * src2 ); +XIDLL void xi_get_font_metrics_font( XinFont * font, int *leading, int *ascent, + int *descent, int *char_width ); +XIDLL int xi_get_fu_height( XI_OBJ * itf ); +XIDLL int xi_get_fu_height_font( XinFont * font ); +XIDLL int xi_get_fu_width( XI_OBJ * itf ); +XIDLL int xi_get_fu_width_font( XinFont * font ); +XIDLL void xi_get_hsb_rect( XI_OBJ * xi_obj, XinRect * rctp ); +XIDLL XI_OBJ *xi_get_itf_from_id( int id ); +XIDLL XinRect *xi_get_rect_internal( XI_OBJ * xi_obj, XinRect * rctp, XinRect * old_win_rct, + XinRect * new_win_rct ); +XIDLL void xi_get_sb_rect( XI_OBJ * xi_obj, XinRect * rctp ); +XIDLL void xi_move_to( XinWindow win, XinPoint pnt ); +XIDLL void xi_draw_line( XinWindow win, XinPoint pnt ); +XIDLL void xi_scroll_rect( XinWindow win, XinRect * rct, int delta_x, int delta_y ); +XIDLL BOOLEAN xi_pt_in_rect( XinRect * rct, XinPoint pnt ); +XIDLL BOOLEAN xi_half_baked( XinWindow win ); +XIDLL void xi_init_sysvals( void ); +XIDLL void xi_make_obj_visible( XI_OBJ * xi_obj ); +XIDLL void xi_menu_enable( XI_OBJ * itf, int tag, BOOLEAN enable ); +XIDLL void xi_move_column_internal( XI_OBJ * column, int position, + BOOLEAN in_hscrolling ); +XIDLL void xi_move_list_hscroll_bar( XI_OBJ * xi_obj ); +XIDLL void xi_move_list_scroll_bar( XI_OBJ * xi_obj ); +XIDLL int xi_obj_to_idx( XI_OBJ * xi_obj ); +XIDLL void xi_realloc_array( void **ptr, int nbr, size_t sz, void *parent ); +XIDLL void xi_set_sysval( XI_SV_TYPE valtype, int value ); +XIDLL void xi_set_trap_obj( XI_OBJ * obj ); +XIDLL void xi_set_update_obj( XI_OBJ * xi_obj ); +XIDLL int xi_get_text_width( XinFont * font, char *s, int len, unsigned long attrib ); +XIDLL char *xi_get_text_string( char *src, unsigned long attrib ); +XIDLL BOOLEAN xi_cr_is_ok( XI_OBJ * xi_obj ); +XIDLL BOOLEAN xi_focus_obj_is_cell_button( XI_OBJ * focus_obj ); +XIDLL void xi_draw_foc_and_dflt( XI_OBJ * focus_obj ); +XIDLL void xi_draw_foc_and_dflt_if_necessary( XI_OBJ * focus_obj, XI_OBJ * next_obj ); +XIDLL BOOLEAN xi_get_native_controls( XI_OBJ * obj ); +XIDLL BOOLEAN xi_XinWindowPaintNeeds( XinWindow win, XinRect * rct ); + +#ifdef TREEDEBUG +#define xi_tree_realloc2(o, s, p) xi_tree_realloc_d2(o, s, p, __LINE__, __FILE__) +char * +XIDLL xi_tree_realloc_d2( char *oldp, size_t size, char *parent, int line, + char *filename ); + +#else +XIDLL char *xi_tree_realloc2( char *oldp, size_t size, char *parent ); + +#endif +XIDLL void xi_draw_icon( XinWindow win, int x, int y, int rid, XinColor fore_color, XinColor back_color ); +XIDLL void xi_draw_text( XinWindow win, XinFont * font, int x, int y, char *s, int len ); +XIDLL BOOLEAN font_compare( XinFont * f1, XinFont * f2 ); +#ifdef XI_USE_TX_SUPPORT +XIDLL void xi_caret_off( XinWindow win ); +#endif +XIDLL void xi_caret_on( XinWindow win, int x, int y, int height, XinRect * clip_rect ); +XIDLL void xi_set_clip( XinWindow win, XinRect * clip ); +XIDLL void xi_draw_dotted_rect( XinWindow win, XinRect * rctp ); + +XIDLL XI_OBJ* xi_get_drag_list_obj( void ); +XIDLL void xi_set_drag_list_obj( XI_OBJ* obj ); + +XIDLL BOOLEAN xi_is_obj( XI_OBJ* obj, XI_OBJ* itf ); + +/*********************************************************************/ +extern XinPen hollow_cpen; +extern XinPen black_cpen; +extern XinPen rubber_cpen; +extern XinBrush white_cbrush; +extern XinBrush hollow_cbrush; +extern XinFont normal_font; + +/*********************************************************************/