1 #include "apricot.h"
2 #include "Application.h"
3 #include "Icon.h"
4 #include "Popup.h"
5 #include "Region.h"
6 #include "Widget.h"
7 #include "Window.h"
8 #include <Widget.inc>
9 
10 #ifdef __cplusplus
11 extern "C" {
12 #endif
13 
14 #undef  set_text
15 #undef  get_text
16 #undef  my
17 #define inherited CDrawable
18 #define enter_method PWidget_vmt selfvmt = ((( PWidget) self)-> self)
19 #define my  selfvmt
20 #define var (( PWidget) self)
21 
22 typedef Bool ActionProc ( Handle self, Handle item, void * params);
23 typedef ActionProc *PActionProc;
24 #define his (( PWidget) child)
25 
26 /* local defines */
27 typedef struct _SingleColor
28 {
29 	Color color;
30 	int   index;
31 } SingleColor, *PSingleColor;
32 
33 static Bool find_dup_msg( PEvent event, int * cmd);
34 static Bool pquery ( Handle window, Handle self, void * v);
35 static Bool get_top_current( Handle self);
36 static Bool sptr( Handle window, Handle self, void * v);
37 static Handle find_tabfoc( Handle self);
38 static Bool showhint_notify ( Handle self, Handle child, void * data);
39 static Bool hint_notify ( Handle self, Handle child, SV * hint);
40 
41 extern void Widget_pack_slaves( Handle self);
42 extern void Widget_place_slaves( Handle self);
43 extern Bool Widget_size_notify( Handle self, Handle child, const Rect* metrix);
44 extern Bool Widget_move_notify( Handle self, Handle child, Point * moveTo);
45 
46 /* init, done & update_sys_handle */
47 void
Widget_init(Handle self,HV * profile)48 Widget_init( Handle self, HV * profile)
49 {
50 	dPROFILE;
51 	enter_method;
52 	SV * sv;
53 	int geometry;
54 
55 	opt_set(optSystemDrawable);
56 	inherited-> init( self, profile);
57 
58 	list_create( &var-> widgets, 0, 8);
59 	var-> tabOrder = -1;
60 
61 	var-> geomInfo. side = 3; /* default pack side is 'top', anchor ='center' */
62 	var-> geomInfo. anchorx = var-> geomInfo. anchory = 1;
63 
64 	my-> update_sys_handle( self, profile);
65 	/* props init */
66 	/* font and colors */
67 	SvHV_Font( pget_sv( font), &Font_buffer, "Widget::init");
68 	my-> set_widgetClass        ( self, pget_i( widgetClass  ));
69 	my-> set_color              ( self, pget_i( color        ));
70 	my-> set_backColor          ( self, pget_i( backColor    ));
71 	my-> set_font               ( self, Font_buffer);
72 	opt_assign( optOwnerBackColor, pget_B( ownerBackColor));
73 	opt_assign( optOwnerColor    , pget_B( ownerColor));
74 	opt_assign( optOwnerFont     , pget_B( ownerFont));
75 	opt_assign( optOwnerHint     , pget_B( ownerHint));
76 	opt_assign( optOwnerShowHint , pget_B( ownerShowHint));
77 	opt_assign( optOwnerPalette  , pget_B( ownerPalette));
78 	my-> colorIndex( self, true,  ciHiliteText,   pget_i( hiliteColor)      );
79 	my-> colorIndex( self, true,  ciHilite,       pget_i( hiliteBackColor)  );
80 	my-> colorIndex( self, true,  ciDisabledText, pget_i( disabledColor)    );
81 	my-> colorIndex( self, true,  ciDisabled,     pget_i( disabledBackColor));
82 	my-> colorIndex( self, true,  ciLight3DColor, pget_i( light3DColor)     );
83 	my-> colorIndex( self, true,  ciDark3DColor,  pget_i( dark3DColor)      );
84 	my-> set_palette( self, pget_sv( palette));
85 
86 	/* light props */
87 	my-> set_autoEnableChildren ( self, pget_B( autoEnableChildren));
88 	my-> set_briefKeys          ( self, pget_B( briefKeys));
89 	my-> set_buffered           ( self, pget_B( buffered));
90 	my-> set_clipChildren       ( self, pget_B( clipChildren));
91 	my-> set_cursorVisible      ( self, pget_B( cursorVisible));
92 	my-> set_dndAware           ( self, pget_sv( dndAware));
93 	my-> set_growMode           ( self, pget_i( growMode));
94 	my-> set_helpContext        ( self, pget_sv( helpContext));
95 	my-> set_hint               ( self, pget_sv( hint));
96 	my-> set_firstClick         ( self, pget_B( firstClick));
97 	{
98 		Point hotSpot;
99 		Handle icon = pget_H( pointerIcon);
100 		prima_read_point( pget_sv( pointerHotSpot), (int*)&hotSpot, 2, "Array panic on 'pointerHotSpot'");
101 		if ( icon != NULL_HANDLE && !kind_of( icon, CIcon)) {
102 			warn("Illegal object reference passed to Widget::pointerIcon");
103 			icon = NULL_HANDLE;
104 		}
105 		apc_pointer_set_user( self, icon, hotSpot);
106 	}
107 	my-> set_pointerType        ( self, pget_i( pointerType));
108 	my-> set_selectingButtons   ( self, pget_i( selectingButtons));
109 	my-> set_selectable         ( self, pget_B( selectable));
110 	my-> set_showHint           ( self, pget_B( showHint));
111 	my-> set_tabOrder           ( self, pget_i( tabOrder));
112 	my-> set_tabStop            ( self, pget_B( tabStop));
113 	my-> set_text               ( self, pget_sv( text));
114 
115 	opt_assign( optScaleChildren, pget_B( scaleChildren));
116 
117 	/* subcomponents props */
118 	my-> popupColorIndex( self, true, ciFore,         pget_i( popupColor)              );
119 	my-> popupColorIndex( self, true, ciBack,         pget_i( popupBackColor)          );
120 	my-> popupColorIndex( self, true, ciHiliteText,   pget_i( popupHiliteColor)        );
121 	my-> popupColorIndex( self, true, ciHilite,       pget_i( popupHiliteBackColor)    );
122 	my-> popupColorIndex( self, true, ciDisabledText, pget_i( popupDisabledColor)      );
123 	my-> popupColorIndex( self, true, ciDisabled,     pget_i( popupDisabledBackColor)  );
124 	my-> popupColorIndex( self, true, ciLight3DColor, pget_i( popupLight3DColor)       );
125 	my-> popupColorIndex( self, true, ciDark3DColor,  pget_i( popupDark3DColor)        );
126 	SvHV_Font( pget_sv( popupFont), &Font_buffer, "Widget::init");
127 	my-> set_popup_font  ( self, Font_buffer);
128 	if ( SvTYPE( sv = pget_sv( popupItems)) != SVt_NULL)
129 		my-> set_popupItems( self, sv);
130 	if ( SvTYPE( sv = pget_sv( accelItems)) != SVt_NULL)
131 		my-> set_accelItems( self, sv);
132 
133 	/* size, position, enabling, visibliity etc. runtime */
134 	{
135 		Point set, set2;
136 		AV * av;
137 		SV ** holder;
138 		NPoint ds = {1,1};
139 
140 		prima_read_point( pget_sv( sizeMin), (int*)&set, 2, "Array panic on 'sizeMin'");
141 		prima_read_point( pget_sv( sizeMax), (int*)&set2, 2, "Array panic on 'sizeMax'");
142 		var-> sizeMax = set2;
143 		my-> set_sizeMin( self, set);
144 		my-> set_sizeMax( self, set2);
145 		prima_read_point( pget_sv( cursorSize), (int*)&set, 2, "Array panic on 'cursorSize'");
146 		my-> set_cursorSize( self, set);
147 		prima_read_point( pget_sv( cursorPos), (int*)&set, 2, "Array panic on 'cursorPos'");
148 		my-> set_cursorPos( self, set);
149 
150 		av = ( AV *) SvRV( pget_sv( designScale));
151 		holder = av_fetch( av, 0, 0);
152 		ds. x = holder ? SvNV( *holder) : 1;
153 		if ( !holder) warn("Array panic on 'designScale'");
154 		holder = av_fetch( av, 1, 0);
155 		ds. y = holder ? SvNV( *holder) : 1;
156 		if ( !holder) warn("Array panic on 'designScale'");
157 		my-> set_designScale( self, ds);
158 	}
159 	my-> set_enabled     ( self, pget_B( enabled));
160 	if ( !pexist( originDontCare) || !pget_B( originDontCare)) {
161 		Point pos;
162 		pos. x = pget_i( left);
163 		pos. y = pget_i( bottom);
164 		my-> set_origin( self, pos);
165 	} else
166 		var-> pos = my-> get_origin( self);
167 
168 	if ( !pexist( sizeDontCare  ) || !pget_B( sizeDontCare  )) {
169 		Point size;
170 		size. x = pget_i( width);
171 		size. y = pget_i( height);
172 		my-> set_size( self, size);
173 	} else
174 		var-> virtualSize = my-> get_size( self);
175 	var-> geomSize = var-> virtualSize;
176 
177 	geometry = pget_i(geometry);
178 	if ( geometry == gtGrowMode ) {
179 		Bool x = 0, y = 0;
180 		if ( pget_B( centered)) { x = 1; y = 1; };
181 		if ( pget_B( x_centered) || ( var-> growMode & gmXCenter)) x = 1;
182 		if ( pget_B( y_centered) || ( var-> growMode & gmYCenter)) y = 1;
183 		if ( x || y) my-> set_centered( self, x, y);
184 		var-> geomInfo. x = x;
185 		var-> geomInfo. y = y;
186 	}
187 
188 	opt_assign( optPackPropagate, pget_B( packPropagate));
189 	my-> set_packInfo( self, pget_sv( packInfo));
190 	my-> set_placeInfo( self, pget_sv( placeInfo));
191 	my-> set_geometry( self, geometry);
192 
193 	my-> set_shape       ( self, pget_H(  shape));
194 	my-> set_visible     ( self, pget_B( visible));
195 	if ( pget_B( capture)) my-> set_capture( self, 1, NULL_HANDLE);
196 	if ( pget_B( current)) my-> set_current( self, 1);
197 	CORE_INIT_TRANSIENT(Widget);
198 
199 	{
200 		SV * widgets = pget_sv( widgets);
201 		if ( SvTYPE( widgets) != SVt_NULL) {
202 			dSP;
203 			ENTER;
204 			SAVETMPS;
205 			PUSHMARK( sp);
206 			XPUSHs( var-> mate);
207 			XPUSHs( sv_2mortal( newSVsv( widgets)));
208 			PUTBACK;
209 			perl_call_method( "widgets", G_DISCARD);
210 			SPAGAIN;
211 			PUTBACK;
212 			FREETMPS;
213 			LEAVE;
214 		}
215 	}
216 }
217 
218 void
Widget_update_sys_handle(Handle self,HV * profile)219 Widget_update_sys_handle( Handle self, HV * profile)
220 {
221 	dPROFILE;
222 	enter_method;
223 	Handle    owner;
224 	Bool      clipOwner, layered, syncPaint, transparent;
225 	ApiHandle parentHandle;
226 	if (!(
227 		pexist( owner) ||
228 		pexist( syncPaint) ||
229 		pexist( clipOwner) ||
230 		pexist( layered) ||
231 		pexist( transparent)
232 	)) return;
233 
234 	owner        = pexist( owner)        ? pget_H( owner)        : var-> owner;
235 	clipOwner    = pexist( clipOwner)    ? pget_B( clipOwner)    : my-> get_clipOwner( self);
236 	parentHandle = pexist( parentHandle) ? pget_i( parentHandle) : apc_widget_get_parent_handle( self);
237 	layered      = pexist( layered)      ? pget_B( layered)      : my-> get_layered(self);
238 	syncPaint    = pexist( syncPaint)    ? pget_B( syncPaint)    : my-> get_syncPaint( self);
239 	transparent  = pexist( transparent)  ? pget_B( transparent)  : my-> get_transparent( self);
240 
241 	if ( parentHandle) {
242 		if (( owner != application) && clipOwner)
243 			croak("Cannot accept 'parentHandle' for non-application child and clip-owner widget");
244 	}
245 
246 	if ( !apc_widget_create( self, owner, syncPaint, clipOwner, transparent, parentHandle, layered))
247 		croak( "Cannot create widget");
248 
249 	pdelete( transparent);
250 	pdelete( syncPaint);
251 	pdelete( clipOwner);
252 	pdelete( parentHandle);
253 	pdelete( layered);
254 }
255 
256 void
Widget_done(Handle self)257 Widget_done( Handle self)
258 {
259 	if ( var-> dndAware != NULL ) {
260 		free( var-> dndAware );
261 		var-> dndAware = NULL;
262 	}
263 	if ( var-> text ) sv_free( var->text);
264 	var-> text = NULL;
265 	apc_widget_destroy( self);
266 	if ( var-> hint ) sv_free( var->hint);
267 	var-> hint = NULL;
268 	free( var-> helpContext);
269 	var-> helpContext = NULL;
270 
271 	if ( var-> owner) {
272 		Handle * enum_lists = PWidget( var-> owner)-> enum_lists;
273 		while ( enum_lists) {
274 			unsigned int i, count;
275 			count = (unsigned int) enum_lists[1];
276 			for ( i = 2; i < count + 2; i++) {
277 				if ( self == enum_lists[i])
278 					enum_lists[i] = NULL_HANDLE;
279 			}
280 			enum_lists = ( Handle*) enum_lists[0];
281 		}
282 	}
283 
284 	list_destroy( &var-> widgets);
285 	inherited-> done( self);
286 }
287 
288 /* ::a */
289 void
Widget_attach(Handle self,Handle objectHandle)290 Widget_attach( Handle self, Handle objectHandle)
291 {
292 	if ( objectHandle == NULL_HANDLE) return;
293 	if ( var-> stage > csNormal) return;
294 	if ( kind_of( objectHandle, CWidget)) {
295 		if ( list_index_of( &var-> widgets, objectHandle) >= 0) {
296 			warn( "Object attach failed");
297 			return;
298 		}
299 		list_add( &var-> widgets, objectHandle);
300 	}
301 	inherited-> attach( self, objectHandle);
302 }
303 
304 /*::b */
305 Bool
Widget_begin_paint(Handle self)306 Widget_begin_paint( Handle self)
307 {
308 	Bool ok;
309 	if ( !inherited-> begin_paint( self))
310 		return false;
311 	if ( !( ok = apc_widget_begin_paint( self, false))) {
312 		inherited-> end_paint( self);
313 		perl_error();
314 	}
315 	return ok;
316 }
317 
318 Bool
Widget_begin_paint_info(Handle self)319 Widget_begin_paint_info( Handle self)
320 {
321 	Bool ok;
322 	if ( is_opt( optInDraw))     return true;
323 	if ( !inherited-> begin_paint_info( self))
324 		return false;
325 	if ( !( ok = apc_widget_begin_paint_info( self))) {
326 		inherited-> end_paint_info( self);
327 		perl_error();
328 	}
329 	return ok;
330 }
331 
332 
333 void
Widget_bring_to_front(Handle self)334 Widget_bring_to_front( Handle self)
335 {
336 	if ( opt_InPaint) return;
337 	apc_widget_set_z_order( self, NULL_HANDLE, true);
338 }
339 
340 /*::c */
341 Bool
Widget_can_close(Handle self)342 Widget_can_close( Handle self)
343 {
344 	enter_method;
345 	Event ev = { cmClose};
346 	return ( var-> stage <= csNormal) ? my-> message( self, &ev) : true;
347 }
348 
349 Bool
Widget_can_propagate_key(Handle self)350 Widget_can_propagate_key( Handle self)
351 {
352 	return true;
353 }
354 
355 void
Widget_cleanup(Handle self)356 Widget_cleanup( Handle self)
357 {
358 	Handle ptr;
359 	enter_method;
360 
361 	/* disconnect all geometry slaves */
362 	ptr = var-> packSlaves;
363 	while ( ptr) {
364 		PWidget( ptr)-> geometry = gtDefault;
365 		ptr = PWidget( ptr)-> geomInfo. next;
366 	}
367 	var-> packSlaves = NULL_HANDLE;
368 	ptr = var-> placeSlaves;
369 	while ( ptr) {
370 		PWidget( ptr)-> geometry = gtDefault;
371 		ptr = PWidget( ptr)-> geomInfo. next;
372 	}
373 	var-> placeSlaves = NULL_HANDLE;
374 
375 	my-> set_geometry( self, gtDefault);
376 
377 	if ( application && (( PApplication) application)-> hintUnder == self)
378 		my-> set_hintVisible( self, 0);
379 
380 	{
381 		int i;
382 		for ( i = 0; i < var-> widgets. count; i++)
383 			Object_destroy( var-> widgets. items[i]);
384 	}
385 
386 	if ( var-> accelTable) {
387 		unprotect_object(var-> accelTable);
388 		//my-> detach( self, var-> accelTable, true);
389 		var-> accelTable = NULL_HANDLE;
390 	}
391 
392 	if ( var-> popupMenu ) {
393 		unprotect_object(var-> popupMenu);
394 		//my-> detach( self, var-> popupMenu, true);
395 		var-> popupMenu = NULL_HANDLE;
396 	}
397 
398 	inherited-> cleanup( self);
399 }
400 
401 
402 Bool
Widget_close(Handle self)403 Widget_close( Handle self)
404 {
405 	Bool canClose;
406 	enter_method;
407 	if ( var-> stage > csNormal) return true;
408 	if (( canClose = my-> can_close( self))) {
409 		Object_destroy( self);
410 	}
411 	return canClose;
412 }
413 
414 Bool
Widget_custom_paint(Handle self)415 Widget_custom_paint( Handle self)
416 {
417 	PList  list;
418 	void * ret;
419 	enter_method;
420 	if ( my-> on_paint != Widget_on_paint) return true;
421 	if ( var-> eventIDs == NULL) return false;
422 	ret = hash_fetch( var-> eventIDs, "Paint", 5);
423 	if ( ret == NULL) return false;
424 	list = var-> events + PTR2UV( ret) - 1;
425 	return list-> count > 0;
426 }
427 
428 /*::d */
429 void
Widget_detach(Handle self,Handle objectHandle,Bool kill)430 Widget_detach( Handle self, Handle objectHandle, Bool kill)
431 {
432 	enter_method;
433 	if ( kind_of( objectHandle, CWidget)) {
434 		list_delete( &var-> widgets, objectHandle);
435 		if ( var-> currentWidget == objectHandle && objectHandle != NULL_HANDLE)
436 			my-> set_currentWidget( self, NULL_HANDLE);
437 	}
438 	inherited-> detach( self, objectHandle, kill);
439 }
440 
441 DNDResp
Widget_dnd_start(Handle self,int dnd_actions,Bool default_pointers)442 Widget_dnd_start(Handle self, int dnd_actions, Bool default_pointers)
443 {
444 	DNDResp ret;
445 	ret.action = apc_dnd_start( self, dnd_actions, default_pointers, &ret.counterpart);
446 	return ret;
447 }
448 
449 /*::e */
450 void
Widget_end_paint(Handle self)451 Widget_end_paint( Handle self)
452 {
453 	if ( !is_opt( optInDraw)) return;
454 	apc_widget_end_paint( self);
455 	inherited-> end_paint( self);
456 }
457 
458 void
Widget_end_paint_info(Handle self)459 Widget_end_paint_info( Handle self)
460 {
461 	if ( !is_opt( optInDrawInfo)) return;
462 	apc_widget_end_paint_info( self);
463 	inherited-> end_paint_info( self);
464 }
465 
466 
467 /*::f */
468 
469 SV*
Widget_fetch_resource(char * className,char * name,char * classRes,char * res,Handle owner,int resType)470 Widget_fetch_resource( char *className, char *name, char *classRes, char *res, Handle owner, int resType)
471 {
472 	char *str = NULL;
473 	Color clr;
474 	void *parm;
475 	Font font;
476 	SV * ret = NULL_SV;
477 	char *r_className, *r_name, *r_classRes, *r_res;
478 
479 	switch ( resType) {
480 	case frColor:
481 		parm = &clr; break;
482 	case frFont:
483 		parm = &font;
484 		bzero( &font, sizeof( font));
485 		break;
486 	default:
487 		parm = &str;
488 		resType = frString;
489 	}
490 
491 	r_className = duplicate_string(className);
492 	r_name      = duplicate_string(name);
493 	r_classRes  = duplicate_string(classRes);
494 	r_res       = duplicate_string(res);
495 
496 	if ( !apc_fetch_resource(
497 		prima_normalize_resource_string( r_className, true),
498 		prima_normalize_resource_string( r_name, false),
499 		prima_normalize_resource_string( r_classRes, true),
500 		prima_normalize_resource_string( r_res, false),
501 		owner, resType, parm))
502 		goto FAIL;
503 
504 	switch ( resType) {
505 	case frColor:
506 		ret = newSViv( clr);
507 		break;
508 	case frFont:
509 		ret = sv_Font2HV( &font);
510 		break;
511 	default:
512 		ret = str ? newSVpv( str, 0) : NULL_SV;
513 		free( str);
514 	}
515 
516 FAIL:
517 	free(r_className);
518 	free(r_name);
519 	free(r_classRes);
520 	free(r_res);
521 
522 	return ret;
523 }
524 
525 Handle
Widget_first(Handle self)526 Widget_first( Handle self)
527 {
528 	return apc_widget_get_z_order( self, zoFirst);
529 }
530 
531 Handle
Widget_first_that(Handle self,void * actionProc,void * params)532 Widget_first_that( Handle self, void * actionProc, void * params)
533 {
534 	Handle child  = NULL_HANDLE;
535 	int i, count  = var-> widgets. count;
536 	Handle * list;
537 	if ( actionProc == NULL || count == 0) return NULL_HANDLE;
538 	if (!(list = allocn( Handle, count + 2))) return NULL_HANDLE;
539 
540 	list[0] = (Handle)( var-> enum_lists);
541 	list[1] = (Handle)( count);
542 	var-> enum_lists = list;
543 	memcpy( list + 2, var-> widgets. items, sizeof( Handle) * count);
544 
545 	for ( i = 2; i < count + 2; i++)
546 	{
547 		if ( list[i] && (( PActionProc) actionProc)( self, list[ i], params))
548 		{
549 			child = list[ i];
550 			break;
551 		}
552 	}
553 	var-> enum_lists = (Handle*)(*list);
554 	free( list);
555 	return child;
556 }
557 
558 /*::g */
559 
560 /*::h */
561 
562 #define evOK ( var-> evStack[ var-> evPtr - 1])
563 #define objCheck if ( var-> stage > csNormal) return
564 
565 static Bool
dnd_event_wanted(Handle self,PEvent event)566 dnd_event_wanted(Handle self, PEvent event)
567 {
568 	Bool r;
569 	SV * ret;
570 	if ( var-> dndAware == NULL) return false;
571 	if ( strcmp(var->dndAware, "1") == 0) return true;
572 	ENTER;
573 	SAVETMPS;
574 	ret = call_perl( event->dnd.clipboard, "has_format", "<s", var->dndAware);
575 	r = ret ? SvTRUE( ret) : false;
576 	FREETMPS;
577 	LEAVE;
578 	return r;
579 }
580 
581 static void
handle_drag_begin(Handle self,PEvent event)582 handle_drag_begin( Handle self, PEvent event)
583 {
584 	enter_method;
585 	if ( !dnd_event_wanted(self, event)) {
586 		opt_clear(optDropSession);
587 		return;
588 	}
589 	opt_set(optDropSession);
590 	my-> notify( self, "<sHiiPH", "DragBegin",
591 		event-> dnd. clipboard,
592 		event-> dnd. action,
593 		event-> dnd. modmap,
594 		event-> dnd. where,
595 		event-> dnd. counterpart
596 	);
597 }
598 
599 static void
handle_drag_over(Handle self,PEvent event)600 handle_drag_over( Handle self, PEvent event)
601 {
602 	dPROFILE;
603 	enter_method;
604 	HV * profile;
605 	SV * ref;
606 
607 	if ( !is_opt(optDropSession)) {
608 		Point size = apc_widget_get_size(self);
609 		event-> dnd.allow      = 0;
610 		event-> dnd.pad.x      = event-> dnd.pad.y = 0;
611 		event-> dnd.pad.width  = size.x;
612 		event-> dnd.pad.height = size.y;
613 		return;
614 	}
615 
616 	profile = newHV();
617 	ref = newRV_noinc((SV*) profile);
618 
619 	pset_i(allow,1);
620 	pset_i(action,dndCopy);
621 	my-> notify( self, "<sHiiPHS", "DragOver",
622 		event-> dnd. clipboard,
623 		event-> dnd. action,
624 		event-> dnd. modmap,
625 		event-> dnd. where,
626 		event-> dnd. counterpart,
627 		ref
628 	);
629 
630 	event-> dnd. allow  = pexist(allow)  ? pget_i(allow)  : 1;
631 	event-> dnd. action = pexist(action) ? pget_i(action) : dndCopy;
632 	memset( &event-> dnd.pad, 0, sizeof(Rect));
633 	if ( pexist(pad)) {
634 		int rect[4];
635 		prima_read_point( pget_sv(pad), rect, 4, "Array panic on 'pad'");
636 		event->dnd.pad.x      = rect[0];
637 		event->dnd.pad.y      = rect[1];
638 		event->dnd.pad.width  = rect[2];
639 		event->dnd.pad.height = rect[3];
640 	}
641 
642 	sv_free(ref);
643 }
644 
645 static void
handle_drag_end(Handle self,PEvent event)646 handle_drag_end( Handle self, PEvent event)
647 {
648 	dPROFILE;
649 	enter_method;
650 	HV * profile;
651 	SV * ref;
652 
653 	if ( !is_opt(optDropSession)) {
654 		event-> dnd. allow = 0;
655 		return;
656 	}
657 	opt_clear(optDropSession);
658 
659 	profile = newHV();
660 	ref = newRV_noinc((SV*) profile);
661 
662 	pset_i(allow, 1);
663 	pset_i(action, event->dnd.action);
664 	my-> notify( self, "<sHiiPHS", "DragEnd",
665 		event-> dnd. allow ? event-> dnd.clipboard : NULL_HANDLE,
666 		event-> dnd. action,
667 		event-> dnd. modmap,
668 		event-> dnd. where,
669 		event-> dnd. counterpart,
670 		ref
671 	);
672 	event-> dnd. allow  = pexist(allow)  ? pget_i(allow)  : 1;
673 	event-> dnd. action = pexist(action) ? pget_i(action) : dndCopy;
674 
675 	sv_free(ref);
676 }
677 
678 static void
handle_drag_query(Handle self,PEvent event)679 handle_drag_query( Handle self, PEvent event)
680 {
681 	dPROFILE;
682 	enter_method;
683 	HV * profile = newHV();
684 	SV * ref = newRV_noinc((SV*) profile);
685 	pset_i(allow, event->dnd.allow);
686 	my-> notify( self, "<siHS", "DragQuery", event->dnd.modmap, event->dnd.counterpart, ref);
687 	if (pexist(allow))
688 		event-> dnd.allow = pget_i(allow);
689 	event-> dnd.action = pexist(action) ? pget_i(action) : 0;
690 	sv_free(ref);
691 }
692 
693 static void
handle_key_down(Handle self,PEvent event)694 handle_key_down( Handle self, PEvent event)
695 {
696 	enter_method;
697 	int i;
698 	int rep = event-> key. repeat;
699 	Handle next = NULL_HANDLE;
700 	if ( is_opt( optBriefKeys))
701 		rep = 1;
702 	else
703 		event-> key. repeat = 1;
704 	for ( i = 0; i < rep; i++) {
705 		my-> notify( self, "<siiii", "KeyDown",
706 			event-> key.code, event-> key. key, event-> key. mod, event-> key. repeat);
707 		objCheck;
708 		if ( evOK) {
709 			Event ev = *event;
710 			ev. key. source = self;
711 			ev. cmd         = var-> owner ? cmDelegateKey : cmTranslateAccel;
712 			ev. key. subcmd = 0;
713 			if ( !my-> message( self, &ev)) {
714 				my-> clear_event( self);
715 				return;
716 			}
717 			objCheck;
718 		}
719 		if ( !evOK) break;
720 
721 		switch( event-> key. key) {
722 		case kbF1:
723 		case kbHelp:
724 			my-> help( self);
725 			my-> clear_event( self);
726 			return;
727 		case kbLeft:
728 			next = my-> next_positional( self, -1, 0);
729 			break;
730 		case kbRight:
731 			next = my-> next_positional( self, 1, 0);
732 			break;
733 		case kbUp:
734 			next = my-> next_positional( self, 0, 1);
735 			break;
736 		case kbDown:
737 			next = my-> next_positional( self, 0, -1);
738 			break;
739 		case kbTab:
740 			next = my-> next_tab( self, true);
741 			break;
742 		case kbBackTab:
743 			next = my-> next_tab( self, false);
744 			break;
745 		default:;
746 		}
747 		if ( next) {
748 			CWidget( next)-> set_selected( next, true);
749 			objCheck;
750 			my-> clear_event( self);
751 			return;
752 		}
753 	}
754 }
755 
756 static void
handle_delegate_key(Handle self,PEvent event)757 handle_delegate_key( Handle self, PEvent event)
758 {
759 	enter_method;
760 	switch ( event-> key. subcmd) {
761 		case 0: {
762 			Event ev = *event;
763 			ev. cmd         = cmTranslateAccel;
764 			if ( !my-> message( self, &ev)) {
765 				my-> clear_event( self);
766 				return;
767 			}
768 			objCheck;
769 
770 			if ( my-> first_that( self, (void*)prima_accel_notify, &ev)) {
771 				my-> clear_event( self);
772 				return;
773 			}
774 			objCheck;
775 			ev. cmd         = cmDelegateKey;
776 			ev. key. subcmd = 1;
777 			if ( my-> first_that( self, (void*)prima_accel_notify, &ev)) {
778 				my-> clear_event( self);
779 				return;
780 			}
781 			if ( var-> owner && my->can_propagate_key(self))
782 			{
783 				if ( var-> owner == application)
784 					ev. cmd = cmTranslateAccel;
785 				else
786 					ev. key. subcmd = 0;
787 				ev. key. source = self;
788 				if (!(((( PWidget) var-> owner)-> self)-> message( var-> owner, &ev))) {
789 					objCheck;
790 					my-> clear_event( self);
791 					return;
792 				}
793 			}
794 		}
795 		break;
796 		case 1: {
797 			Event ev = *event;
798 			ev. cmd  = cmTranslateAccel;
799 			if ( my-> first_that( self, (void*)prima_accel_notify, &ev)) {
800 				my-> clear_event( self);
801 				return;
802 			}
803 			objCheck;
804 			ev = *event;
805 			if ( my-> first_that( self, (void*)prima_accel_notify, &ev)) {
806 				my-> clear_event( self);
807 				return;
808 			}
809 		}
810 		break;
811 	}
812 }
813 
814 static void
handle_move(Handle self,PEvent event)815 handle_move( Handle self, PEvent event)
816 {
817 	enter_method;
818 	Bool doNotify = false;
819 	Point oldP;
820 	if ( var-> stage == csNormal && var-> evQueue == NULL) {
821 		doNotify = true;
822 	} else if ( var-> stage > csNormal) {
823 		return;
824 	} else if ( var-> evQueue != NULL) {
825 		int i = list_first_that( var-> evQueue, (void*)find_dup_msg, &event-> cmd);
826 		PEvent n;
827 		if ( i < 0) {
828 			if ( !( n = alloc1( Event))) goto MOVE_EVENT;
829 			memcpy( n, event, sizeof( Event));
830 			n-> gen. B = 1;
831 			n-> gen. R. left = n-> gen. R. bottom = 0;
832 			list_add( var-> evQueue, ( Handle) n);
833 		} else
834 			n = ( PEvent) list_at( var-> evQueue, i);
835 		n-> gen. P = event-> gen. P;
836 	}
837 MOVE_EVENT:;
838 	if ( !event-> gen. B)
839 		my-> first_that( self, (void*) Widget_move_notify, &event-> gen. P);
840 	if ( doNotify) oldP = var-> pos;
841 	var-> pos = event-> gen. P;
842 	if ( doNotify &&
843 		(oldP. x != event-> gen. P. x ||
844 			oldP. y != event-> gen. P. y)) {
845 		my-> notify( self, "<sPP", "Move", oldP, event-> gen. P);
846 		objCheck;
847 		if ( var->geometry == gtGrowMode && var-> growMode & gmCenter)
848 			my-> set_centered( self, var-> growMode & gmXCenter, var-> growMode & gmYCenter);
849 	}
850 }
851 
852 static void
handle_popup(Handle self,PEvent event)853 handle_popup( Handle self, PEvent event)
854 {
855 	enter_method;
856 	Handle org = self;
857 	my-> notify( self, "<siP", "Popup", event-> gen. B, event-> gen. P. x, event-> gen. P. y);
858 	objCheck;
859 	if ( evOK) {
860 		while ( self) {
861 			PPopup p = ( PPopup) CWidget( self)-> get_popup( self);
862 			if ( p && p-> self-> get_autoPopup(( Handle) p)) {
863 				Point px = event-> gen. P;
864 				apc_widget_map_points( org,  true,  1, &px);
865 				apc_widget_map_points( self, false, 1, &px);
866 				p-> self-> popup(( Handle) p, px. x, px. y ,0,0,0,0);
867 				CWidget( org)-> clear_event( org);
868 				return;
869 			}
870 			self = var-> owner;
871 		}
872 	}
873 }
874 
875 static void
handle_size(Handle self,PEvent event)876 handle_size( Handle self, PEvent event)
877 {
878 	enter_method;
879 	/* expecting new size in P, old & new size in R. */
880 	Bool doNotify = false;
881 	if ( var-> stage == csNormal && var-> evQueue == NULL) {
882 		doNotify = true;
883 	} else if ( var-> stage > csNormal) {
884 		return;
885 	} else if ( var-> evQueue != NULL) {
886 		int i = list_first_that( var-> evQueue, (void*)find_dup_msg, &event-> cmd);
887 		PEvent n;
888 		if ( i < 0) {
889 			if ( !( n = alloc1( Event))) goto SIZE_EVENT;
890 			memcpy( n, event, sizeof( Event));
891 			n-> gen. B = 1;
892 			n-> gen. R. left = n-> gen. R. bottom = 0;
893 			list_add( var-> evQueue, ( Handle) n);
894 		} else
895 			n = ( PEvent) list_at( var-> evQueue, i);
896 		n-> gen. P. x = n-> gen. R. right  = event-> gen. P. x;
897 		n-> gen. P. y = n-> gen. R. top    = event-> gen. P. y;
898 	}
899 SIZE_EVENT:;
900 	if ( var->geometry == gtGrowMode && var-> growMode & gmCenter)
901 		my-> set_centered( self, var-> growMode & gmXCenter, var-> growMode & gmYCenter);
902 	if ( !event-> gen. B)
903 		my-> first_that( self, (void*) Widget_size_notify, &event-> gen. R);
904 	if ( doNotify) {
905 		Point oldSize;
906 		oldSize. x = event-> gen. R. left;
907 		oldSize. y = event-> gen. R. bottom;
908 		my-> notify( self, "<sPP", "Size", oldSize, event-> gen. P);
909 	}
910 	Widget_pack_slaves( self);
911 	Widget_place_slaves( self) ;
912 }
913 
Widget_handle_event(Handle self,PEvent event)914 void Widget_handle_event( Handle self, PEvent event)
915 {
916 	enter_method;
917 	inherited-> handle_event ( self, event);
918 	objCheck;
919 	switch ( event-> cmd)
920 	{
921 		case cmCalcBounds:
922 		{
923 			Point min, max;
924 			min = var-> sizeMin;
925 			max = var-> sizeMax;
926 			if (( min. x > 0) && ( min. x > event-> gen. R. right  )) event-> gen. R. right  = min. x;
927 			if (( min. y > 0) && ( min. y > event-> gen. R. top    )) event-> gen. R. top    = min. y;
928 			if (( max. x > 0) && ( max. x < event-> gen. R. right  )) event-> gen. R. right  = max. x;
929 			if (( max. y > 0) && ( max. y < event-> gen. R. top    )) event-> gen. R. top    = max. y;
930 		}
931 		break;
932 		case cmSetup:
933 			if ( !is_opt( optSetupComplete)) {
934 				opt_set( optSetupComplete);
935 				my-> notify( self, "<s", "Setup");
936 			}
937 			break;
938 		case cmRepaint:
939 			my-> repaint( self);
940 			break;
941 		case cmPaint        :
942 			if ( !opt_InPaint && !my-> get_locked( self))
943 				if ( inherited-> begin_paint( self)) {
944 					if ( apc_widget_begin_paint( self, true)) {
945 						Bool flag = exception_block(true);
946 						my-> notify( self, "<sH", "Paint", self);
947 						exception_block(flag);
948 						if ( var-> stage == csNormal ) apc_widget_end_paint( self);
949 						EXCEPTION_CHECK_RAISE;
950 						objCheck;
951 						inherited-> end_paint( self);
952 					} else
953 						inherited-> end_paint( self);
954 				}
955 			break;
956 		case cmEnable       :
957 			my-> notify( self, "<s", "Enable");
958 			break;
959 		case cmDisable      :
960 			my-> notify( self, "<s", "Disable");
961 			break;
962 		case cmReceiveFocus :
963 			my-> notify( self, "<s", "Enter");
964 			break;
965 		case cmReleaseFocus :
966 			my-> notify( self, "<s", "Leave");
967 			break;
968 		case cmShow         :
969 			my-> notify( self, "<s", "Show");
970 			break;
971 		case cmHide         :
972 			my-> notify( self, "<s", "Hide");
973 			break;
974 		case cmHint:
975 			my-> notify( self, "<si", "Hint", event-> gen. B);
976 			break;
977 		case cmClose        :
978 			if ( my-> first_that( self, (void*)pquery, NULL)) {
979 				my-> clear_event( self);
980 				return;
981 			}
982 			objCheck;
983 			my-> notify( self, "<s", "Close");
984 			break;
985 		case cmZOrderChanged:
986 			my-> notify( self, "<s", "ZOrderChanged");
987 			break;
988 		case cmClick:
989 			my-> notify( self, "<s", "Click");
990 			break;
991 		case cmColorChanged:
992 			if ( !kind_of( event-> gen. source, CPopup))
993 				my-> notify( self, "<si", "ColorChanged", event-> gen. i);
994 			else
995 				var-> popupColor[ event-> gen. i] =
996 					apc_menu_get_color( event-> gen. source, event-> gen. i);
997 			break;
998 		case cmFontChanged:
999 			if ( !kind_of( event-> gen. source, CPopup))
1000 				my-> notify( self, "<s", "FontChanged");
1001 			else
1002 				apc_menu_get_font( event-> gen. source, &var-> popupFont);
1003 			break;
1004 		case cmMenu:
1005 			if ( event-> gen. H) {
1006 				char buffer[16], *context;
1007 				context = ((( PAbstractMenu) event-> gen. H)-> self)-> make_id_context( event-> gen. H, event-> gen. i, buffer);
1008 				my-> notify( self, "<sHs", "Menu", event-> gen. H, context);
1009 			}
1010 			break;
1011 		case cmMouseClick:
1012 			my-> notify( self, "<siiPi", "MouseClick",
1013 				event-> pos. button, event-> pos. mod, event-> pos. where, event-> pos. dblclk);
1014 			break;
1015 		case cmMouseDown:
1016 			if ((( PApplication) application)-> hintUnder == self)
1017 				my-> set_hintVisible( self, 0);
1018 			objCheck;
1019 			if (((event-> pos. button & var-> selectingButtons) != 0) && my-> get_selectable( self))
1020 				my-> set_selected( self, true);
1021 			objCheck;
1022 			my-> notify( self, "<siiP", "MouseDown",
1023 				event-> pos. button, event-> pos. mod, event-> pos. where);
1024 			break;
1025 		case cmMouseUp:
1026 			my-> notify( self, "<siiP", "MouseUp",
1027 				event-> pos. button, event-> pos. mod, event-> pos. where);
1028 			break;
1029 		case cmMouseMove:
1030 			if ((( PApplication) application)-> hintUnder == self)
1031 				my-> set_hintVisible( self, -1);
1032 			objCheck;
1033 			my-> notify( self, "<siP", "MouseMove", event-> pos. mod, event -> pos. where);
1034 			break;
1035 		case cmMouseWheel:
1036 			my-> notify( self, "<siPi", "MouseWheel",
1037 				event-> pos. mod, event -> pos. where,
1038 				event-> pos. button); /* +n*delta == up, -n*delta == down */
1039 			break;
1040 		case cmMouseEnter:
1041 			my-> notify( self, "<siP", "MouseEnter", event-> pos. mod, event -> pos. where);
1042 			objCheck;
1043 			if ( application && is_opt( optShowHint) && ((( PApplication) application)-> options. optShowHint) && var-> hint && SvCUR(var-> hint))
1044 			{
1045 				PApplication app = ( PApplication) application;
1046 				app-> self-> set_hint_action( application, self, true, true);
1047 			}
1048 			break;
1049 		case cmMouseLeave:
1050 			if ( application && is_opt( optShowHint)) {
1051 				PApplication app = ( PApplication) application;
1052 				app-> self-> set_hint_action( application, self, false, true);
1053 			}
1054 			my-> notify( self, "<s", "MouseLeave");
1055 			break;
1056 		case cmKeyDown:
1057 			handle_key_down(self, event);
1058 			break;
1059 		case cmDelegateKey:
1060 			handle_delegate_key( self, event );
1061 			break;
1062 		case cmTranslateAccel:
1063 		{
1064 			int key = CAbstractMenu-> translate_key( NULL_HANDLE, event-> key. code, event-> key. key, event-> key. mod);
1065 			if ( my-> first_that_component( self, (void*)prima_find_accel, &key)) {
1066 				my-> clear_event( self);
1067 				return;
1068 			}
1069 			objCheck;
1070 			my-> notify( self, "<siii", "TranslateAccel",
1071 				event-> key.code, event-> key. key, event-> key. mod);
1072 			break;
1073 		}
1074 		case cmKeyUp:
1075 			my-> notify( self, "<siii", "KeyUp",
1076 			event-> key.code, event-> key. key, event-> key. mod);
1077 			break;
1078 		case cmMenuCmd:
1079 			if ( event-> gen. source)
1080 				((( PAbstractMenu) event-> gen. source)-> self)->
1081 					sub_call_id( event-> gen. source, event-> gen. i);
1082 			break;
1083 		case cmMove:
1084 			handle_move(self, event);
1085 			break;
1086 		case cmPopup:
1087 			handle_popup(self, event);
1088 			break;
1089 		case cmSize:
1090 			handle_size( self, event);
1091 			break;
1092 		case cmDragBegin       :
1093 			handle_drag_begin( self, event );
1094 			break;
1095 		case cmDragOver       :
1096 			handle_drag_over( self, event );
1097 			break;
1098 		case cmDragEnd        :
1099 			handle_drag_end( self, event );
1100 			break;
1101 		case cmDragQuery       :
1102 			handle_drag_query( self, event );
1103 			break;
1104 		case cmDragResponse     :
1105 			my-> notify( self, "<siiH", "DragResponse",
1106 				event->dnd.allow, event->dnd.action, event->dnd.counterpart);
1107 			break;
1108 		case cmMenuItemMeasure  :
1109 		case cmMenuItemPaint    :
1110 			{
1111 				Handle menu = event->gen.H;
1112 				event->gen.H = self;
1113 				PComponent(menu)->self->handle_event(menu, event);
1114 				break;
1115 			}
1116 	}
1117 }
1118 
1119 void
Widget_hide(Handle self)1120 Widget_hide( Handle self)
1121 {
1122 	enter_method;
1123 	my-> set_visible( self, false);
1124 }
1125 
1126 void
Widget_hide_cursor(Handle self)1127 Widget_hide_cursor( Handle self)
1128 {
1129 	enter_method;
1130 	if ( my-> get_cursorVisible( self))
1131 		my-> set_cursorVisible( self, false);
1132 	else
1133 		var-> cursorLock++;
1134 }
1135 
1136 /*::i */
1137 void
Widget_insert_behind(Handle self,Handle widget)1138 Widget_insert_behind ( Handle self, Handle widget)
1139 {
1140 	apc_widget_set_z_order( self, widget, 0);
1141 }
1142 
1143 void
Widget_invalidate_rect(Handle self,Rect rect)1144 Widget_invalidate_rect( Handle self, Rect rect)
1145 {
1146 	enter_method;
1147 	if ( !opt_InPaint && ( var-> stage == csNormal) && !my-> get_locked( self))
1148 		apc_widget_invalidate_rect( self, &rect);
1149 }
1150 
1151 
1152 Bool
Widget_is_child(Handle self,Handle owner)1153 Widget_is_child( Handle self, Handle owner)
1154 {
1155 	if ( !owner)
1156 		return false;
1157 	while ( self) {
1158 		if ( self == owner)
1159 			return true;
1160 		self = var-> owner;
1161 	}
1162 	return false;
1163 }
1164 
1165 /*::j */
1166 /*::k */
1167 void
Widget_key_event(Handle self,int command,int code,int key,int mod,int repeat,Bool post)1168 Widget_key_event( Handle self, int command, int code, int key, int mod, int repeat, Bool post)
1169 {
1170 	Event ev;
1171 	if ( command != cmKeyDown && command != cmKeyUp) return;
1172 	memset( &ev, 0, sizeof( ev));
1173 	if ( repeat <= 0) repeat = 1;
1174 	ev. cmd = command;
1175 	ev. key. code   = code;
1176 	ev. key. key    = key;
1177 	ev. key. mod    = mod;
1178 	ev. key. repeat = repeat;
1179 	apc_message( self, &ev, post);
1180 }
1181 
1182 /*::l */
1183 Handle
Widget_last(Handle self)1184 Widget_last( Handle self)
1185 {
1186 	return apc_widget_get_z_order( self, zoLast);
1187 }
1188 
1189 Bool
Widget_lock(Handle self)1190 Widget_lock( Handle self)
1191 {
1192 	var-> lockCount++;
1193 	return true;
1194 }
1195 
1196 /*::m */
1197 void
Widget_mouse_event(Handle self,int command,int button,int mod,int x,int y,Bool dbl,Bool post)1198 Widget_mouse_event( Handle self, int command, int button, int mod, int x, int y, Bool dbl, Bool post)
1199 {
1200 	Event ev;
1201 	if ( command != cmMouseDown
1202 		&& command != cmMouseUp
1203 		&& command != cmMouseClick
1204 		&& command != cmMouseMove
1205 		&& command != cmMouseWheel
1206 		&& command != cmMouseEnter
1207 		&& command != cmMouseLeave
1208 	) return;
1209 
1210 	memset( &ev, 0, sizeof( ev));
1211 	ev. cmd = command;
1212 	ev. pos. where. x = x;
1213 	ev. pos. where. y = y;
1214 	ev. pos. mod    = mod;
1215 	ev. pos. button = button;
1216 	if ( command == cmMouseClick) ev. pos. dblclk = dbl;
1217 	apc_message( self, &ev, post);
1218 }
1219 
1220 /*::n */
1221 Handle
Widget_next(Handle self)1222 Widget_next( Handle self)
1223 {
1224 	return apc_widget_get_z_order( self, zoNext);
1225 }
1226 
1227 static void
fill_tab_candidates(PList list,Handle level)1228 fill_tab_candidates( PList list, Handle level)
1229 {
1230 	int i;
1231 	PList w = &(PWidget( level)-> widgets);
1232 	for ( i = 0; i < w-> count; i++) {
1233 		Handle x = w-> items[i];
1234 		if ( CWidget( x)-> get_visible( x) && CWidget( x)-> get_enabled( x)) {
1235 			if ( CWidget( x)-> get_selectable( x) && CWidget( x)-> get_tabStop( x))
1236 				list_add( list, x);
1237 			fill_tab_candidates( list, x);
1238 		}
1239 	}
1240 }
1241 
1242 Handle
Widget_next_positional(Handle self,int dx,int dy)1243 Widget_next_positional( Handle self, int dx, int dy)
1244 {
1245 	Handle horizon = self;
1246 
1247 	int i, maxDiff = INT_MAX;
1248 	Handle max = NULL_HANDLE;
1249 	List candidates;
1250 	Point p[2];
1251 
1252 	int minor[2], major[2], axis, extraDiff, ir[4];
1253 
1254 	/*
1255 		In order to compute positional difference, using four penalties.
1256 		To simplify algorithm, Rect will be translated to int[4] and
1257 		minor, major and extraDiff assigned to array indices for those
1258 		steps - minor for first and third, major for second and extraDiff for last one.
1259 	*/
1260 
1261 	axis = ( dx == 0) ? dy : dx;
1262 	minor[0] = ( dx == 0) ? 0 : 1;
1263 	minor[1] = minor[0] + 2;
1264 	extraDiff = major[(axis < 0) ? 0 : 1] = ( dx == 0) ? 1 : 0;
1265 	major[(axis < 0) ? 1 : 0] = extraDiff + 2;
1266 	extraDiff = ( dx == 0) ? (( axis < 0) ? 0 : 2) : (( axis < 0) ? 1 : 3);
1267 
1268 	while ( PWidget( horizon)-> owner) {
1269 		if (
1270 			( PWidget( horizon)-> options. optSystemSelectable) || /* fast check for CWindow */
1271 			( PWidget( horizon)-> options. optModalHorizon)
1272 			) break;
1273 		horizon = PWidget( horizon)-> owner;
1274 	}
1275 
1276 	if ( !CWidget( horizon)-> get_visible( horizon) ||
1277 		!CWidget( horizon)-> get_enabled( horizon)) return NULL_HANDLE;
1278 
1279 	list_create( &candidates, 64, 64);
1280 	fill_tab_candidates( &candidates, horizon);
1281 
1282 	p[0].x = p[0].y = 0;
1283 	p[1] = CWidget( self)-> get_size( self);
1284 	apc_widget_map_points( self, true, 2, p);
1285 	apc_widget_map_points( horizon, false, 2, p);
1286 	ir[0] = p[0].x; ir[1] = p[0].y; ir[2] = p[1].x; ir[3] = p[1].y;
1287 
1288 	for ( i = 0; i < candidates. count; i++) {
1289 		int    diff, ix[4];
1290 		Handle x = candidates. items[i];
1291 
1292 		if ( x == self) continue;
1293 
1294 		p[0].x = p[0].y = 0;
1295 		p[1] = CWidget( x)-> get_size( x);
1296 		apc_widget_map_points( x, true, 2, p);
1297 		apc_widget_map_points( horizon, false, 2, p);
1298 		ix[0] = p[0].x; ix[1] = p[0].y; ix[2] = p[1].x; ix[3] = p[1].y;
1299 
1300 		/* First step - checking if the widget is subject to comparison. It is not,
1301 			if it's minor axis is not contiguous with self's */
1302 
1303 		if ( ix[ minor[0]] > ir[ minor[1]] || ix[ minor[1]] < ir[ minor[0]])
1304 			continue;
1305 
1306 		/* Using x100 penalty for distance in major axis - and discarding those that
1307 			of different sign */
1308 		diff = ( ix[ major[ 1]] - ir[ major[0]]) * 100 * axis;
1309 		if ( diff < 0)
1310 			continue;
1311 
1312 		/* Adding x10 penalty for incomplete minor axis congruence. Addition goes in tenths,
1313 			in a way to not allow congruence overweight major axis distance */
1314 		if ( ix[ minor[0]] > ir[ minor[0]])
1315 			diff += ( ix[ minor[0]] - ir[ minor[0]]) * 100 / ( ir[ minor[1]] - ir[ minor[0]]);
1316 		if ( ix[ minor[1]] < ir[ minor[1]])
1317 			diff += ( ir[ minor[1]] - ix[ minor[1]]) * 100 / ( ir[ minor[1]] - ir[ minor[0]]);
1318 
1319 		/* Adding 'distance from level' x1 penalty */
1320 		if (( ix[ extraDiff] - ir[ extraDiff]) * axis < 0)
1321 			diff += abs( ix[ extraDiff] - ir[ extraDiff]);
1322 
1323 		if ( diff < maxDiff) {
1324 			max = x;
1325 			maxDiff = diff;
1326 		}
1327 	}
1328 
1329 	list_destroy( &candidates);
1330 
1331 	return max;
1332 }
1333 
compare_taborders_forward(const void * a,const void * b)1334 static int compare_taborders_forward( const void *a, const void *b)
1335 {
1336 	if ((*(PWidget*) a)-> tabOrder < (*(PWidget*) b)-> tabOrder)
1337 		return -1; else
1338 	if ((*(PWidget*) a)-> tabOrder > (*(PWidget*) b)-> tabOrder)
1339 		return 1;
1340 	else
1341 		return 0;
1342 }
1343 
compare_taborders_backward(const void * a,const void * b)1344 static int compare_taborders_backward( const void *a, const void *b)
1345 {
1346 	if ((*(PWidget*) a)-> tabOrder < (*(PWidget*) b)-> tabOrder)
1347 		return 1; else
1348 	if ((*(PWidget*) a)-> tabOrder > (*(PWidget*) b)-> tabOrder)
1349 		return -1;
1350 	else
1351 		return 0;
1352 }
1353 
1354 static int
do_taborder_candidates(Handle level,Handle who,int (* compareProc)(const void *,const void *),int * stage,Handle * result)1355 do_taborder_candidates( Handle level, Handle who,
1356 	int (*compareProc)(const void *, const void *),
1357 	int * stage, Handle * result)
1358 {
1359 	int i, fsel = -1;
1360 	PList w = &(PWidget( level)-> widgets);
1361 	Handle * ordered;
1362 
1363 	if ( w-> count == 0) return true;
1364 
1365 	ordered = ( Handle *) malloc( w-> count * sizeof( Handle));
1366 	if ( !ordered) return true;
1367 
1368 	memcpy( ordered, w-> items, w-> count * sizeof( Handle));
1369 	qsort( ordered, w-> count, sizeof( Handle), compareProc);
1370 
1371 	/* finding current widget in the group */
1372 	for ( i = 0; i < w-> count; i++) {
1373 		Handle x = ordered[i];
1374 		if ( CWidget( x)-> get_current( x)) {
1375 			fsel = i;
1376 			break;
1377 		}
1378 	}
1379 	if ( fsel < 0) fsel = 0;
1380 
1381 	for ( i = 0; i < w-> count; i++) {
1382 		int j;
1383 		Handle x;
1384 
1385 		j = i + fsel;
1386 		if ( j >= w-> count) j -= w-> count;
1387 
1388 		x = ordered[j];
1389 		if ( CWidget( x)-> get_visible( x) && CWidget( x)-> get_enabled( x)) {
1390 			if ( CWidget( x)-> get_selectable( x) && CWidget( x)-> get_tabStop( x)) {
1391 				if ( *result == NULL_HANDLE) *result = x;
1392 				switch( *stage) {
1393 				case 0: /* nothing found yet */
1394 					if ( x == who) *stage = 1;
1395 					break;
1396 				default:
1397 					/* next widget after 'who' is ours */
1398 					*result = x;
1399 					free( ordered);
1400 					return false;
1401 				}
1402 			}
1403 			if ( !do_taborder_candidates( x, who, compareProc, stage, result)) {
1404 				free( ordered);
1405 				return false; /* fall through */
1406 			}
1407 		}
1408 	}
1409 	free( ordered);
1410 	return true;
1411 }
1412 
1413 Handle
Widget_next_tab(Handle self,Bool forward)1414 Widget_next_tab( Handle self, Bool forward)
1415 {
1416 	Handle horizon = self, result = NULL_HANDLE;
1417 	int stage = 0;
1418 
1419 	while ( PWidget( horizon)-> owner) {
1420 		if (
1421 			( PWidget( horizon)-> options. optSystemSelectable) || /* fast check for CWindow */
1422 			( PWidget( horizon)-> options. optModalHorizon)
1423 			) break;
1424 		horizon = PWidget( horizon)-> owner;
1425 	}
1426 
1427 	if ( !CWidget( horizon)-> get_visible( horizon) ||
1428 		!CWidget( horizon)-> get_enabled( horizon)) return NULL_HANDLE;
1429 
1430 	do_taborder_candidates( horizon, self,
1431 		forward ? compare_taborders_forward : compare_taborders_backward,
1432 		&stage, &result);
1433 	if ( result == self) result = NULL_HANDLE;
1434 	return result;
1435 }
1436 
1437 /*::o */
1438 /*::p */
1439 
1440 
1441 void
Widget_post_message(Handle self,SV * info1,SV * info2)1442 Widget_post_message( Handle self, SV * info1, SV * info2)
1443 {
1444 	PPostMsg p;
1445 	Event ev = { cmPost};
1446 	if ( var-> stage > csNormal) return;
1447 	if (!( p = alloc1( PostMsg))) return;
1448 	p-> info1  = newSVsv( info1);
1449 	p-> info2  = newSVsv( info2);
1450 	p-> h = self;
1451 	if ( var-> postList == NULL)
1452 		var-> postList = plist_create( 8, 8);
1453 	list_add( var-> postList, ( Handle) p);
1454 	ev. gen. p = p;
1455 	ev. gen. source = ev. gen. H = self;
1456 	apc_message( self, &ev, true);
1457 }
1458 
1459 Handle
Widget_prev(Handle self)1460 Widget_prev( Handle self)
1461 {
1462 	return apc_widget_get_z_order( self, zoPrev);
1463 }
1464 
1465 Bool
Widget_process_accel(Handle self,int key)1466 Widget_process_accel( Handle self, int key)
1467 {
1468 	enter_method;
1469 	if ( my-> first_that_component( self, (void*)prima_find_accel, &key)) return true;
1470 	return kind_of( var-> owner, CWidget) ?
1471 			((( PWidget) var-> owner)-> self)->process_accel( var-> owner, key) : false;
1472 }
1473 
1474 /*::q */
1475 /*::r */
1476 void
Widget_repaint(Handle self)1477 Widget_repaint( Handle self)
1478 {
1479 	enter_method;
1480 	if ( !opt_InPaint && ( var-> stage == csNormal) && !my-> get_locked( self))
1481 		apc_widget_invalidate_rect( self, NULL);
1482 }
1483 
1484 /*::s */
1485 int
Widget_scroll(Handle self,int dx,int dy,Rect * confine,Rect * clip,Bool withChildren)1486 Widget_scroll( Handle self, int dx, int dy, Rect *confine, Rect *clip, Bool withChildren)
1487 {
1488 	enter_method;
1489 	if ( !opt_InPaint && ( var-> stage == csNormal) && !my-> get_locked( self))
1490 		return apc_widget_scroll( self, dx, dy, confine, clip, withChildren);
1491 	return scrError;
1492 }
1493 
1494 int
Widget_scroll_REDEFINED(Handle self,int dx,int dy,Rect * confine,Rect * clip,Bool withChildren)1495 Widget_scroll_REDEFINED( Handle self, int dx, int dy, Rect *confine, Rect *clip, Bool withChildren)
1496 {
1497 	warn("Invalid call of Widget::scroll");
1498 	return scrError;
1499 }
1500 
XS(Widget_scroll_FROMPERL)1501 XS( Widget_scroll_FROMPERL)
1502 {
1503 	dPROFILE;
1504 	dXSARGS;
1505 	Handle self;
1506 	int dx, dy, ret;
1507 	Rect *confine = NULL;
1508 	Rect *clip = NULL;
1509 	Rect confine_rect, clip_rect;
1510 	Bool withChildren = false;
1511 	HV *profile;
1512 	int rect[4];
1513 
1514 	if ( items < 3 || (items - 3) % 2) goto invalid_usage;
1515 	if (!( self = gimme_the_mate( ST(0)))) goto invalid_usage;
1516 	dx = SvIV( ST(1));
1517 	dy = SvIV( ST(2));
1518 	profile = parse_hv( ax, sp, items, mark, 3, "Widget::scroll");
1519 	if ( pexist( confineRect)) {
1520 		prima_read_point( pget_sv( confineRect), rect, 4, "Array panic on 'confineRect'");
1521 		confine = &confine_rect;
1522 		confine-> left = rect[0];
1523 		confine-> bottom = rect[1];
1524 		confine-> right = rect[2];
1525 		confine-> top = rect[3];
1526 	}
1527 	if ( pexist( clipRect)) {
1528 		prima_read_point( pget_sv( clipRect), rect, 4, "Array panic on 'clipRect'");
1529 		clip = &clip_rect;
1530 		clip-> left = rect[0];
1531 		clip-> bottom = rect[1];
1532 		clip-> right = rect[2];
1533 		clip-> top = rect[3];
1534 	}
1535 	if ( pexist( withChildren)) withChildren = pget_B( withChildren);
1536 	sv_free((SV*)profile);
1537 	ret = Widget_scroll( self, dx, dy, confine, clip, withChildren);
1538 	SPAGAIN;
1539 	SP -= items;
1540 	XPUSHs( sv_2mortal( newSViv( ret)));
1541 	PUTBACK;
1542 	return;
1543 invalid_usage:
1544 	croak ("Invalid usage of %s", "Widget::scroll");
1545 }
1546 
1547 void
Widget_send_to_back(Handle self)1548 Widget_send_to_back( Handle self)
1549 {
1550 	apc_widget_set_z_order( self, NULL_HANDLE, false);
1551 }
1552 
1553 void
Widget_set(Handle self,HV * profile)1554 Widget_set( Handle self, HV * profile)
1555 {
1556 	dPROFILE;
1557 	enter_method;
1558 	Handle postOwner = NULL_HANDLE;
1559 	AV *order = NULL;
1560 	int geometry = gtDefault;
1561 
1562 	if ( pexist(__ORDER__)) order = (AV*)SvRV(pget_sv( __ORDER__));
1563 
1564 	if ( pexist( owner)) {
1565 		if ( !my-> validate_owner( self, &postOwner, profile))
1566 			croak( "Illegal 'owner' reference passed to %s::%s", my-> className, "set");
1567 		if ( postOwner != var-> owner) {
1568 			if ( is_opt( optOwnerColor)) {
1569 				my-> set_color( self, CWidget( postOwner)-> get_color( postOwner));
1570 				opt_set( optOwnerColor);
1571 			}
1572 			if ( is_opt( optOwnerBackColor)) {
1573 				my-> set_backColor( self, CWidget( postOwner)-> get_backColor( postOwner));
1574 				opt_set( optOwnerBackColor);
1575 			}
1576 			if ( is_opt( optOwnerShowHint)) {
1577 				Bool newSH = ( postOwner == application) ? 1 :
1578 					CWidget( postOwner)-> get_showHint( postOwner);
1579 				my-> set_showHint( self, newSH);
1580 				opt_set( optOwnerShowHint);
1581 			}
1582 			if ( is_opt( optOwnerHint)) {
1583 				my-> set_hint( self, CWidget( postOwner)-> get_hint( postOwner));
1584 				opt_set( optOwnerHint);
1585 			}
1586 			if ( is_opt( optOwnerFont)) {
1587 				my-> set_font ( self, CWidget( postOwner)-> get_font( postOwner));
1588 				opt_set( optOwnerFont);
1589 			}
1590 		}
1591 		if ( var-> geometry != gtDefault) {
1592 			geometry = var-> geometry;
1593 			my-> set_geometry( self, gtDefault);
1594 		}
1595 	}
1596 
1597 	/* geometry manipulations */
1598 	{
1599 #define iLEFT   0
1600 #define iRIGHT  1
1601 #define iTOP    2
1602 #define iBOTTOM 3
1603 #define iWIDTH  4
1604 #define iHEIGHT 5
1605 		int i, count;
1606 		Bool exists[ 6];
1607 		int  values[ 6];
1608 
1609 		bzero( values, sizeof(values));
1610 		if ( pexist( origin))
1611 		{
1612 			int set[2];
1613 			if (order && !pexist(left))   av_push( order, newSVpv("left",0));
1614 			if (order && !pexist(bottom)) av_push( order, newSVpv("bottom",0));
1615 			prima_read_point( pget_sv( origin), set, 2, "Array panic on 'origin'");
1616 			pset_i( left,   set[0]);
1617 			pset_i( bottom, set[1]);
1618 			pdelete( origin);
1619 		}
1620 		if ( pexist( rect))
1621 		{
1622 			int rect[4];
1623 			if (order && !pexist(left)) av_push( order, newSVpv("left",0));
1624 			if (order && !pexist(bottom)) av_push( order, newSVpv("bottom",0));
1625 			if (order && !pexist(width)) av_push( order, newSVpv("width",0));
1626 			if (order && !pexist(height)) av_push( order, newSVpv("height",0));
1627 			prima_read_point( pget_sv( rect), rect, 4, "Array panic on 'rect'");
1628 			pset_i( left,   rect[0]);
1629 			pset_i( bottom, rect[1]);
1630 			pset_i( width,  rect[2] - rect[0]);
1631 			pset_i( height, rect[3] - rect[1]);
1632 			pdelete( rect);
1633 		}
1634 		if ( pexist( size))
1635 		{
1636 			int set[2];
1637 			if (order && !pexist(width)) av_push( order, newSVpv("width",0));
1638 			if (order && !pexist(height)) av_push( order, newSVpv("height",0));
1639 			prima_read_point( pget_sv( size), set, 2, "Array panic on 'size'");
1640 			pset_i( width,  set[0]);
1641 			pset_i( height, set[1]);
1642 			pdelete( size);
1643 		}
1644 
1645 		if (( exists[ iLEFT]   = pexist( left)))    values[ iLEFT]   = pget_i( left);
1646 		if (( exists[ iRIGHT]  = pexist( right)))   values[ iRIGHT]  = pget_i( right);
1647 		if (( exists[ iTOP]    = pexist( top)))     values[ iTOP]    = pget_i( top);
1648 		if (( exists[ iBOTTOM] = pexist( bottom ))) values[ iBOTTOM] = pget_i( bottom);
1649 		if (( exists[ iWIDTH]  = pexist( width)))   values[ iWIDTH]  = pget_i( width);
1650 		if (( exists[ iHEIGHT] = pexist( height)))  values[ iHEIGHT] = pget_i( height);
1651 
1652 		count = 0;
1653 		for ( i = 0; i < 6; i++) if ( exists[ i]) count++;
1654 
1655 		if ( count > 1) {
1656 			if ( exists[ iWIDTH] && exists[ iRIGHT] && exists[ iLEFT]) {
1657 				exists[ iRIGHT] = 0;
1658 				count--;
1659 			}
1660 			if ( exists[ iHEIGHT] && exists[ iTOP] && exists[ iBOTTOM]) {
1661 				exists[ iTOP] = 0;
1662 				count--;
1663 			}
1664 			if ( exists[ iRIGHT] && exists[ iLEFT]) {
1665 				exists[ iWIDTH] = 1;
1666 				values[ iWIDTH] = values[ iRIGHT] - values[ iLEFT];
1667 				exists[ iRIGHT] = 0;
1668 			}
1669 			if ( exists[ iTOP] && exists[ iBOTTOM]) {
1670 				exists[ iHEIGHT] = 1;
1671 				values[ iHEIGHT] = values[ iTOP] - values[ iBOTTOM];
1672 				exists[ iTOP]    = 0;
1673 			}
1674 
1675 			if (
1676 				( count == 2) &&
1677 				(
1678 					( exists[ iLEFT]  && exists[ iBOTTOM]) ||
1679 					( exists[ iWIDTH] && exists[ iHEIGHT])
1680 				)
1681 				) {
1682 				Point p;
1683 				if ( exists[ iLEFT]) {
1684 					p. x = values[ iLEFT];
1685 					p. y = values[ iBOTTOM];
1686 					my-> set_origin( self, p);
1687 				} else {
1688 					p. x = values[ iWIDTH];
1689 					p. y = values[ iHEIGHT];
1690 					my-> set_size( self, p);
1691 				}
1692 			} else {
1693 				Rect r;
1694 				if ( !exists[ iWIDTH] || !exists[ iHEIGHT]) {
1695 					Point sz;
1696 					sz = my-> get_size( self);
1697 					if ( !exists[ iWIDTH])  values[ iWIDTH]  = sz. x;
1698 					if ( !exists[ iHEIGHT]) values[ iHEIGHT] = sz. y;
1699 					exists[ iWIDTH] = exists[ iHEIGHT] = 1;
1700 				}
1701 				if ( ( !exists[ iLEFT]   && !exists[ iRIGHT]) ||
1702 					( !exists[ iBOTTOM] && !exists[ iTOP])) {
1703 					Point pos;
1704 					pos = my-> get_origin( self);
1705 					if ( !exists[ iLEFT])   values[ iLEFT]   = pos. x;
1706 					if ( !exists[ iBOTTOM]) values[ iBOTTOM] = pos. y;
1707 					exists[ iLEFT] = exists[ iBOTTOM] = 1;
1708 				}
1709 				if ( !exists[ iLEFT]) {
1710 					exists[ iLEFT] = 1;
1711 					values[ iLEFT] = values[ iRIGHT] - values[ iWIDTH];
1712 				}
1713 				if ( !exists[ iBOTTOM]) {
1714 					exists[ iBOTTOM] = 1;
1715 					values[ iBOTTOM] = values[ iTOP] - values[ iHEIGHT];
1716 				}
1717 				r. left   = values[ iLEFT];
1718 				r. bottom = values[ iBOTTOM];
1719 				r. right  = values[ iLEFT] + values[ iWIDTH];
1720 				r. top    = values[ iBOTTOM] + values[ iHEIGHT];
1721 				my-> set_rect( self, r);
1722 			}
1723 			pdelete( left);
1724 			pdelete( right);
1725 			pdelete( top);
1726 			pdelete( bottom);
1727 			pdelete( width);
1728 			pdelete( height);
1729 		} /* count > 1 */
1730 	}
1731 	if ( pexist( popupFont))
1732 	{
1733 		SvHV_Font( pget_sv( popupFont), &Font_buffer, "Widget::set");
1734 		my-> set_popup_font( self, Font_buffer);
1735 		pdelete( popupFont);
1736 	}
1737 	if ( pexist( pointerIcon) && pexist( pointerHotSpot))
1738 	{
1739 		Point hotSpot;
1740 		Handle icon = pget_H( pointerIcon);
1741 		prima_read_point( pget_sv( pointerHotSpot), (int*)&hotSpot, 2, "Array panic on 'pointerHotSpot'");
1742 		if ( icon != NULL_HANDLE && !kind_of( icon, CIcon)) {
1743 			warn("Illegal object reference passed to Widget.set_pointer_icon");
1744 			icon = NULL_HANDLE;
1745 		}
1746 		apc_pointer_set_user( self, icon, hotSpot);
1747 		if ( var-> pointerType == crUser) my-> first_that( self, (void*)sptr, NULL);
1748 		pdelete( pointerIcon);
1749 		pdelete( pointerHotSpot);
1750 	}
1751 	if ( pexist( designScale))
1752 	{
1753 		AV * av = ( AV *) SvRV( pget_sv( designScale));
1754 		SV ** holder = av_fetch( av, 0, 0);
1755 		NPoint ds = {1,1};
1756 		ds. x = holder ? SvNV( *holder) : 1;
1757 		if ( !holder) warn("Array panic on 'designScale'");
1758 		holder = av_fetch( av, 1, 0);
1759 		ds. y = holder ? SvNV( *holder) : 1;
1760 		if ( !holder) warn("Array panic on 'designScale'");
1761 		my-> set_designScale( self, ds);
1762 		pdelete( designScale);
1763 	}
1764 	if ( pexist( sizeMin)) {
1765 		Point set;
1766 		prima_read_point( pget_sv( sizeMin), (int*)&set, 2, "Array panic on 'sizeMin'");
1767 		my-> set_sizeMin( self, set);
1768 		pdelete( sizeMin);
1769 	}
1770 	if ( pexist( sizeMax)) {
1771 		Point set;
1772 		prima_read_point( pget_sv( sizeMax), (int*)&set, 2, "Array panic on 'sizeMax'");
1773 		my-> set_sizeMax( self, set);
1774 		pdelete( sizeMax);
1775 	}
1776 	if ( pexist( cursorSize)) {
1777 		Point set;
1778 		prima_read_point( pget_sv( cursorSize), (int*)&set, 2, "Array panic on 'cursorSize'");
1779 		my-> set_cursorSize( self, set);
1780 		pdelete( cursorSize);
1781 	}
1782 	if ( pexist( cursorPos)) {
1783 		Point set;
1784 		prima_read_point( pget_sv( cursorPos), (int*)&set, 2, "Array panic on 'cursorPos'");
1785 		my-> set_cursorPos( self, set);
1786 		pdelete( cursorPos);
1787 	}
1788 	if ( pexist( geomSize))
1789 	{
1790 		Point set;
1791 		prima_read_point( pget_sv( geomSize), (int*)&set, 2, "Array panic on 'geomSize'");
1792 		my-> set_geomSize( self, set);
1793 		pdelete( geomSize);
1794 	}
1795 
1796 	inherited-> set( self, profile);
1797 	if ( postOwner) {
1798 		my-> set_tabOrder( self, var-> tabOrder);
1799 		my-> set_geometry( self, geometry);
1800 	}
1801 }
1802 
1803 void
Widget_setup(Handle self)1804 Widget_setup( Handle self)
1805 {
1806 	enter_method;
1807 	if ( var-> geometry == gtGrowMode && ( var-> geomInfo.x != 0 || var-> geomInfo. y != 0 ))
1808 		my-> set_centered( self, var-> geomInfo. x, var-> geomInfo. y);
1809 	if ( get_top_current( self) &&
1810 		my-> get_enabled( self) &&
1811 		my-> get_visible( self))
1812 		my-> set_selected( self, true);
1813 	inherited-> setup( self);
1814 }
1815 
1816 void
Widget_show(Handle self)1817 Widget_show( Handle self)
1818 {
1819 	enter_method;
1820 	my-> set_visible( self, true);
1821 }
1822 
1823 void
Widget_show_cursor(Handle self)1824 Widget_show_cursor( Handle self)
1825 {
1826 	enter_method;
1827 	if ( var-> cursorLock-- <= 0) {
1828 		my-> set_cursorVisible( self, true);
1829 		var-> cursorLock = 0;
1830 	}
1831 }
1832 
1833 /*::t */
1834 /*::u */
1835 
1836 static Bool
repaint_all(Handle owner,Handle self,void * dummy)1837 repaint_all( Handle owner, Handle self, void * dummy)
1838 {
1839 	enter_method;
1840 	my-> repaint( self);
1841 	my-> first_that( self, (void*)repaint_all, NULL);
1842 	return false;
1843 }
1844 
1845 Bool
Widget_unlock(Handle self)1846 Widget_unlock( Handle self)
1847 {
1848 	if ( --var-> lockCount <= 0) {
1849 		var-> lockCount = 0;
1850 		repaint_all( var-> owner, self, NULL);
1851 	}
1852 	return true;
1853 }
1854 
1855 void
Widget_update_view(Handle self)1856 Widget_update_view( Handle self)
1857 {
1858 	if ( !opt_InPaint) apc_widget_update( self);
1859 }
1860 
1861 /*::v */
1862 
1863 Bool
Widget_validate_owner(Handle self,Handle * owner,HV * profile)1864 Widget_validate_owner( Handle self, Handle * owner, HV * profile)
1865 {
1866 	dPROFILE;
1867 	*owner = pget_H( owner);
1868 	if ( !kind_of( *owner, CWidget)) return false;
1869 	return inherited-> validate_owner( self, owner, profile);
1870 }
1871 
1872 /*::w */
1873 /*::x */
1874 /*::y */
1875 /*::z */
1876 
1877 /* get_props() */
1878 
1879 Font
Widget_get_default_font(char * dummy)1880 Widget_get_default_font( char * dummy)
1881 {
1882 	Font font;
1883 	apc_widget_default_font( &font);
1884 	return font;
1885 }
1886 
1887 Font
Widget_get_default_popup_font(char * dummy)1888 Widget_get_default_popup_font( char * dummy)
1889 {
1890 	Font f;
1891 	apc_popup_default_font( &f);
1892 	return f;
1893 }
1894 
1895 
1896 NPoint
Widget_designScale(Handle self,Bool set,NPoint designScale)1897 Widget_designScale( Handle self, Bool set, NPoint designScale)
1898 {
1899 	if ( !set)
1900 		return var-> designScale;
1901 	if ( designScale. x < 0) designScale. x = 0;
1902 	if ( designScale. y < 0) designScale. y = 0;
1903 	var-> designScale = designScale;
1904 	return designScale;
1905 }
1906 
1907 int
Widget_growMode(Handle self,Bool set,int growMode)1908 Widget_growMode( Handle self, Bool set, int growMode)
1909 {
1910 	enter_method;
1911 	Bool x = false, y = false;
1912 	if ( !set)
1913 		return var-> growMode;
1914 	var-> growMode = growMode;
1915 	if ( var-> growMode & gmXCenter) x = true;
1916 	if ( var-> growMode & gmYCenter) y = true;
1917 	if ( var-> geometry == gtGrowMode && (x || y)) my-> set_centered( self, x, y);
1918 	return var-> growMode;
1919 }
1920 
1921 SV *
Widget_get_handle(Handle self)1922 Widget_get_handle( Handle self)
1923 {
1924 	char buf[ 256];
1925 	snprintf( buf, 256, PR_HANDLE_FMT, apc_widget_get_handle( self));
1926 	return newSVpv( buf, 0);
1927 }
1928 
1929 SV *
Widget_get_parent_handle(Handle self)1930 Widget_get_parent_handle( Handle self)
1931 {
1932 	char buf[ 256];
1933 	snprintf( buf, 256, PR_HANDLE_FMT, apc_widget_get_parent_handle( self));
1934 	return newSVpv( buf, 0);
1935 }
1936 
1937 int
Widget_hintVisible(Handle self,Bool set,int hintVisible)1938 Widget_hintVisible( Handle self, Bool set, int hintVisible)
1939 {
1940 	Bool wantVisible;
1941 	if ( !set)
1942 		return PApplication( application)-> hintVisible;
1943 	if ( var-> stage >= csDead) return false;
1944 	wantVisible = ( hintVisible != 0);
1945 	if ( wantVisible == PApplication( application)-> hintVisible) return false;
1946 	if ( wantVisible) {
1947 		if ( SvCUR( var-> hint) == 0) return false;
1948 		if ( hintVisible > 0) PApplication(application)-> hintActive = -1; /* immediate */
1949 	}
1950 	CApplication( application)-> set_hint_action( application, self, wantVisible, false);
1951 	return false;
1952 }
1953 
1954 Bool
Widget_get_locked(Handle self)1955 Widget_get_locked( Handle self)
1956 {
1957 	while ( self) {
1958 		if ( var-> lockCount != 0) return true;
1959 		self = var-> owner;
1960 	}
1961 	return false;
1962 }
1963 
1964 
1965 Handle
Widget_get_parent(Handle self)1966 Widget_get_parent( Handle self)
1967 {
1968 	enter_method;
1969 	return my-> get_clipOwner( self) ? var-> owner : application;
1970 }
1971 
1972 Point
Widget_get_pointer_size(char * dummy)1973 Widget_get_pointer_size( char*dummy)
1974 {
1975 	return apc_pointer_get_size( NULL_HANDLE);
1976 }
1977 
1978 Font
Widget_get_popup_font(Handle self)1979 Widget_get_popup_font( Handle self)
1980 {
1981 	return var-> popupFont;
1982 }
1983 
1984 Handle
Widget_get_selectee(Handle self)1985 Widget_get_selectee( Handle self)
1986 {
1987 	if ( var-> stage > csFrozen) return NULL_HANDLE;
1988 	if ( is_opt( optSelectable))
1989 		return self;
1990 	else if ( var-> currentWidget) {
1991 		PWidget w = ( PWidget) var-> currentWidget;
1992 		if ( w-> options. optSystemSelectable && !w-> self-> get_clipOwner(( Handle) w))
1993 			return ( Handle) w;
1994 		else
1995 			return w-> self-> get_selectee(( Handle) w);
1996 	} else if ( is_opt( optSystemSelectable))
1997 		return self;
1998 	else
1999 		return find_tabfoc( self);
2000 }
2001 
2002 Point
Widget_get_virtual_size(Handle self)2003 Widget_get_virtual_size( Handle self)
2004 {
2005 	return var-> virtualSize;
2006 }
2007 
2008 /* set_props() */
2009 
2010 Bool
Widget_set_capture(Handle self,Bool capture,Handle confineTo)2011 Widget_set_capture( Handle self, Bool capture, Handle confineTo)
2012 {
2013 	if ( opt_InPaint) return false;
2014 	return apc_widget_set_capture( self, capture, confineTo);
2015 }
2016 
2017 void
Widget_set_centered(Handle self,Bool x,Bool y)2018 Widget_set_centered( Handle self, Bool x, Bool y)
2019 {
2020 	enter_method;
2021 	Handle parent = my-> get_parent( self);
2022 	Point size    = CWidget( parent)-> get_size( parent);
2023 	Point mysize  = my-> get_size ( self);
2024 	Point mypos   = my-> get_origin( self);
2025 	Point delta   = {0,0};
2026 
2027 	if ( !x && !y ) return;
2028 
2029 	if ( parent == application ) {
2030 		int i, nrects = 0;
2031 		Box *best = NULL, *rects = apc_application_get_monitor_rects( application, &nrects);
2032 		for ( i = 0; i < nrects; i++) {
2033 			Box * curr = rects + i;
2034 			if ( best == NULL || best-> x > curr->x || best->y > curr->y)
2035 				best = curr;
2036 		}
2037 		if ( best ) {
2038 			delta.x = best->x;
2039 			delta.y = best->y;
2040 			size.x  = best->width;
2041 			size.y  = best->height;
2042 		}
2043 	}
2044 	if ( x) mypos. x = ( size. x - mysize. x) / 2 + delta.x;
2045 	if ( y) mypos. y = ( size. y - mysize. y) / 2 + delta.y;
2046 	my-> set_origin( self, mypos);
2047 }
2048 
2049 void
Widget_set_font(Handle self,Font font)2050 Widget_set_font( Handle self, Font font)
2051 {
2052 	enter_method;
2053 	if ( var-> stage > csFrozen) return;
2054 	if ( !opt_InPaint) my-> first_that( self, (void*)prima_font_notify, &font);
2055 	if ( var-> handle == NULL_HANDLE) return; /* aware of call from Drawable::init */
2056 	if ( opt_InPaint) {
2057 		inherited->set_font(self, font);
2058 	}
2059 	else {
2060 		apc_font_pick( self, &font, & var-> font);
2061 		opt_clear( optOwnerFont);
2062 		apc_widget_set_font( self, & var-> font);
2063 		my-> repaint( self);
2064 	}
2065 }
2066 
2067 void
Widget_set_popup_font(Handle self,Font font)2068 Widget_set_popup_font( Handle self, Font font)
2069 {
2070 	apc_font_pick( self, &font, &var-> popupFont);
2071 }
2072 
2073 /* event handlers */
2074 
2075 void
Widget_on_paint(Handle self,SV * canvas)2076 Widget_on_paint( Handle self, SV * canvas)
2077 {
2078 	int i;
2079 	dSP;
2080 	ENTER;
2081 	SAVETMPS;
2082 	PUSHMARK( sp);
2083 	XPUSHs( canvas);
2084 	for ( i = 0; i < 4; i++)
2085 		XPUSHs( sv_2mortal( newSViv( -1)));
2086 	PUTBACK;
2087 	PERL_CALL_METHOD( "clear", G_DISCARD);
2088 	SPAGAIN;
2089 	PUTBACK;
2090 	FREETMPS;
2091 	LEAVE;
2092 }
2093 
2094 /*
2095 void Widget_on_click( Handle self) {}
2096 void Widget_on_change( Handle self) {}
2097 void Widget_on_close( Handle self) {}
2098 void Widget_on_colorchanged( Handle self, int colorIndex){}
2099 void Widget_on_disable( Handle self) {}
2100 void Widget_on_dragdrop( Handle self, Handle source , int x , int y ) {}
2101 void Widget_on_dragover( Handle self, Handle source , int x , int y , int state ) {}
2102 void Widget_on_enable( Handle self) {}
2103 void Widget_on_enddrag( Handle self, Handle target , int x , int y ) {}
2104 void Widget_on_fontchanged( Handle self) {}
2105 void Widget_on_enter( Handle self) {}
2106 void Widget_on_keydown( Handle self, int code , int key , int shiftState, int repeat ) {}
2107 void Widget_on_keyup( Handle self, int code , int key , int shiftState ) {}
2108 void Widget_on_menu( Handle self, Handle menu, char * variable) {}
2109 void Widget_on_setup( Handle self) {}
2110 void Widget_on_size( Handle self, Point oldSize, Point newSize) {}
2111 void Widget_on_move( Handle self, Point oldPos, Point newPos) {}
2112 void Widget_on_show( Handle self) {}
2113 void Widget_on_hide( Handle self) {}
2114 void Widget_on_hint( Handle self, Bool show) {}
2115 void Widget_on_translateaccel( Handle self, int code , int key , int shiftState ) {}
2116 void Widget_on_zorderchanged( Handle self) {}
2117 void Widget_on_popup( Handle self, Bool mouseDriven, int x, int y) {}
2118 void Widget_on_mouseclick( Handle self, int button , int shiftState , int x , int y , Bool dbl ) {}
2119 void Widget_on_mousedown( Handle self, int button , int shiftState , int x , int y ) {}
2120 void Widget_on_mouseup( Handle self, int button , int shiftState , int x , int y ) {}
2121 void Widget_on_mousemove( Handle self, int shiftState , int x , int y ) {}
2122 void Widget_on_mousewheel( Handle self, int shiftState , int x , int y, int z ) {}
2123 void Widget_on_mouseenter( Handle self, int shiftState , int x , int y ) {}
2124 void Widget_on_mouseleave( Handle self ) {}
2125 void Widget_on_leave( Handle self) {}
2126 */
2127 
2128 
2129 /* static iterators */
prima_kill_all_objects(Handle self,Handle child,void * dummy)2130 Bool prima_kill_all_objects( Handle self, Handle child, void * dummy)
2131 {
2132 	Object_destroy( child); return 0;
2133 }
2134 
find_dup_msg(PEvent event,int * cmd)2135 static Bool find_dup_msg( PEvent event, int * cmd) { return event-> cmd == *cmd; }
2136 
2137 Bool
prima_accel_notify(Handle group,Handle self,PEvent event)2138 prima_accel_notify ( Handle group, Handle self, PEvent event)
2139 {
2140 	enter_method;
2141 	if (( self != event-> key. source) && my-> get_enabled( self))
2142 		return ( var-> stage <= csNormal) ? !my-> message( self, event) : false;
2143 	else
2144 		return false;
2145 }
2146 
2147 static Bool
pquery(Handle window,Handle self,void * v)2148 pquery ( Handle window, Handle self, void * v)
2149 {
2150 	enter_method;
2151 	Event ev = {cmClose};
2152 	return ( var-> stage <= csNormal) ? !my-> message( self, &ev) : false;
2153 }
2154 
2155 Bool
prima_find_accel(Handle self,Handle item,int * key)2156 prima_find_accel( Handle self, Handle item, int * key)
2157 {
2158 	return ( kind_of( item, CAbstractMenu)
2159 				&& CAbstractMenu(item)-> sub_call_key( item, *key));
2160 }
2161 
2162 static Handle
find_tabfoc(Handle self)2163 find_tabfoc( Handle self)
2164 {
2165 	int i;
2166 	Handle toRet;
2167 	for ( i = 0; i < var-> widgets. count; i++) {
2168 		PWidget w = ( PWidget)( var-> widgets. items[ i]);
2169 		if (
2170 			w-> self-> get_selectable(( Handle) w) &&
2171 			w-> self-> get_enabled(( Handle) w)
2172 		)
2173 			return ( Handle) w;
2174 	}
2175 	for ( i = 0; i < var-> widgets. count; i++)
2176 		if (( toRet = find_tabfoc( var-> widgets. items[ i])))
2177 			return toRet;
2178 	return NULL_HANDLE;
2179 }
2180 
2181 
2182 static Bool
get_top_current(Handle self)2183 get_top_current( Handle self)
2184 {
2185 	PWidget o  = ( PWidget) var-> owner;
2186 	Handle  me = self;
2187 	while ( o) {
2188 		if ( o-> currentWidget != me)
2189 			return false;
2190 		me = ( Handle) o;
2191 		o  = ( PWidget) o-> owner;
2192 	}
2193 	return true;
2194 }
2195 
2196 static Bool
sptr(Handle window,Handle self,void * v)2197 sptr( Handle window, Handle self, void * v)
2198 {
2199 	enter_method;
2200 	/* does nothing but refreshes system pointer */
2201 	if ( var-> pointerType == crDefault)
2202 		my-> set_pointerType( self, crDefault);
2203 	return false;
2204 }
2205 
2206 /* static iterators for ownership notifications */
2207 
2208 Bool
prima_font_notify(Handle self,Handle child,void * font)2209 prima_font_notify ( Handle self, Handle child, void * font)
2210 {
2211 	if ( his-> options. optOwnerFont) {
2212 		his-> self-> set_font ( child, *(( PFont) font));
2213 		his-> options. optOwnerFont = 1;
2214 	}
2215 	return false;
2216 }
2217 
2218 static Bool
showhint_notify(Handle self,Handle child,void * data)2219 showhint_notify ( Handle self, Handle child, void * data)
2220 {
2221 	if ( his-> options. optOwnerShowHint) {
2222 		his-> self-> set_showHint ( child, *(( Bool *) data));
2223 		his-> options. optOwnerShowHint = 1;
2224 	}
2225 	return false;
2226 }
2227 
2228 static Bool
hint_notify(Handle self,Handle child,SV * hint)2229 hint_notify ( Handle self, Handle child, SV * hint)
2230 {
2231 	if ( his-> options. optOwnerHint) {
2232 		his-> self-> set_hint( child, hint);
2233 		his-> options. optOwnerHint = 1;
2234 	}
2235 	return false;
2236 }
2237 
2238 Bool
prima_single_color_notify(Handle self,Handle child,void * color)2239 prima_single_color_notify ( Handle self, Handle child, void * color)
2240 {
2241 	PSingleColor s = ( PSingleColor) color;
2242 	if ( his-> options. optOwnerColor && ( s-> index == ciFore))
2243 	{
2244 		his-> self-> colorIndex ( child, true, s-> index, s-> color);
2245 		his-> options. optOwnerColor = 1;
2246 	} else if (( his-> options. optOwnerBackColor) && ( s-> index == ciBack))
2247 	{
2248 		his-> self-> colorIndex ( child, true, s-> index, s-> color);
2249 		his-> options. optOwnerBackColor = 1;
2250 	} else if ( s-> index > ciBack)
2251 		his-> self-> colorIndex ( child, true, s-> index, s-> color);
2252 	return false;
2253 }
2254 
2255 static Bool
auto_enable_children(Handle self,Handle child,void * enable)2256 auto_enable_children( Handle self, Handle child, void * enable)
2257 {
2258 	apc_widget_set_enabled( child, PTR2UV( enable) != 0);
2259 	return false;
2260 }
2261 /* properties section */
2262 
2263 SV *
Widget_accelItems(Handle self,Bool set,SV * accelItems)2264 Widget_accelItems( Handle self, Bool set, SV * accelItems)
2265 {
2266 	dPROFILE;
2267 	enter_method;
2268 	if ( var-> stage > csFrozen) return NULL_SV;
2269 	if ( !set)
2270 		return var-> accelTable ?
2271 			CAbstractMenu( var-> accelTable)-> get_items( var-> accelTable, "", true) : NULL_SV;
2272 	if ( var-> accelTable == NULL_HANDLE) {
2273 		HV * profile = newHV();
2274 		if ( SvTYPE( accelItems)) pset_sv( items, accelItems);
2275 		pset_H ( owner, self);
2276 		my-> set_accelTable( self, create_instance( "Prima::AccelTable"));
2277 		sv_free(( SV *) profile);
2278 	} else
2279 		CAbstractMenu( var-> accelTable)-> set_items( var-> accelTable, accelItems);
2280 	return NULL_SV;
2281 }
2282 
2283 Handle
Widget_accelTable(Handle self,Bool set,Handle accelTable)2284 Widget_accelTable( Handle self, Bool set, Handle accelTable)
2285 {
2286 	if ( var-> stage > csFrozen) return NULL_HANDLE;
2287 	if ( !set)
2288 		return var-> accelTable;
2289 	if ( accelTable && !kind_of( accelTable, CAbstractMenu)) return NULL_HANDLE;
2290 	if ( var->accelTable ) unprotect_object(var-> accelTable);
2291 	var-> accelTable = accelTable;
2292 	if ( var->accelTable ) protect_object(var-> accelTable);
2293 	return NULL_HANDLE;
2294 }
2295 
2296 Color
Widget_backColor(Handle self,Bool set,Color color)2297 Widget_backColor( Handle self, Bool set, Color color)
2298 {
2299 	enter_method;
2300 	if (!set) return my-> colorIndex( self, false, ciBack, 0);
2301 	my-> colorIndex( self, true, ciBack, color);
2302 	return color;
2303 }
2304 
2305 int
Widget_bottom(Handle self,Bool set,int bottom)2306 Widget_bottom( Handle self, Bool set, int bottom)
2307 {
2308 	enter_method;
2309 	Point p = my-> get_origin( self);
2310 	if ( !set)
2311 		return p. y;
2312 	p. y = bottom;
2313 	my-> set_origin( self, p);
2314 	return 0;
2315 }
2316 
2317 Bool
Widget_autoEnableChildren(Handle self,Bool set,Bool autoEnableChildren)2318 Widget_autoEnableChildren( Handle self, Bool set, Bool autoEnableChildren)
2319 {
2320 	if ( !set)
2321 		return is_opt( optAutoEnableChildren);
2322 	opt_assign( optAutoEnableChildren, autoEnableChildren);
2323 	return false;
2324 }
2325 
2326 Bool
Widget_briefKeys(Handle self,Bool set,Bool briefKeys)2327 Widget_briefKeys( Handle self, Bool set, Bool briefKeys)
2328 {
2329 	if ( !set)
2330 		return is_opt( optBriefKeys);
2331 	opt_assign( optBriefKeys, briefKeys);
2332 	return false;
2333 }
2334 
2335 Bool
Widget_buffered(Handle self,Bool set,Bool buffered)2336 Widget_buffered( Handle self, Bool set, Bool buffered)
2337 {
2338 	if ( !set)
2339 		return is_opt( optBuffered);
2340 	if ( !opt_InPaint)
2341 		opt_assign( optBuffered, buffered);
2342 	return false;
2343 }
2344 
2345 Bool
Widget_clipChildren(Handle self,Bool set,Bool clip_by_children)2346 Widget_clipChildren( Handle self, Bool set, Bool clip_by_children)
2347 {
2348 	if ( set)
2349 		return apc_widget_set_clip_by_children(self, clip_by_children);
2350 	else
2351 		return apc_widget_get_clip_by_children(self);
2352 }
2353 
2354 Bool
Widget_clipOwner(Handle self,Bool set,Bool clipOwner)2355 Widget_clipOwner( Handle self, Bool set, Bool clipOwner)
2356 {
2357 	HV * profile;
2358 	enter_method;
2359 	if ( !set)
2360 		return apc_widget_get_clip_owner( self);
2361 	profile = newHV();
2362 	pset_i( clipOwner, clipOwner);
2363 	my-> set( self, profile);
2364 	sv_free(( SV *) profile);
2365 	return false;
2366 }
2367 
2368 Color
Widget_color(Handle self,Bool set,Color color)2369 Widget_color( Handle self, Bool set, Color color)
2370 {
2371 	enter_method;
2372 	if (!set)
2373 		return my-> colorIndex( self, false, ciFore, 0);
2374 	return my-> colorIndex( self, true, ciFore, color);
2375 }
2376 
2377 Color
Widget_colorIndex(Handle self,Bool set,int index,Color color)2378 Widget_colorIndex( Handle self, Bool set, int index, Color color)
2379 {
2380 	if ( !set) {
2381 		if ( index < 0 || index > ciMaxId) return clInvalid;
2382 		switch ( index) {
2383 		case ciFore:
2384 			return opt_InPaint ? inherited-> get_color ( self) : apc_widget_get_color( self, ciFore);
2385 		case ciBack:
2386 			return opt_InPaint ? inherited-> get_backColor ( self) : apc_widget_get_color( self, ciBack);
2387 		default:
2388 			return apc_widget_get_color( self, index);
2389 		}
2390 	} else {
2391 		enter_method;
2392 		SingleColor s;
2393 		s. color = color;
2394 		s. index = index;
2395 		if (( index < 0) || ( index > ciMaxId)) return clInvalid;
2396 		if ( !opt_InPaint) my-> first_that( self, (void*)prima_single_color_notify, &s);
2397 
2398 		if ( var-> handle == NULL_HANDLE) return clInvalid; /* aware of call from Drawable::init */
2399 		if ((( color & clSysFlag) != 0) && (( color & wcMask) == 0))
2400 			color |= var-> widgetClass;
2401 		if ( opt_InPaint) {
2402 			switch ( index) {
2403 				case ciFore:
2404 					inherited-> set_color ( self, color);
2405 					break;
2406 				case ciBack:
2407 					inherited-> set_backColor ( self, color);
2408 					break;
2409 				default:
2410 					apc_widget_set_color ( self, color, index);
2411 			}
2412 		} else {
2413 			switch ( index) {
2414 				case ciFore:
2415 					opt_clear( optOwnerColor);
2416 					break;
2417 				case ciBack:
2418 					opt_clear( optOwnerBackColor);
2419 					break;
2420 			}
2421 			apc_widget_set_color( self, color, index);
2422 			my-> repaint( self);
2423 		}
2424 	}
2425 	return 0;
2426 }
2427 
2428 Bool
Widget_current(Handle self,Bool set,Bool current)2429 Widget_current( Handle self, Bool set, Bool current)
2430 {
2431 	PWidget o;
2432 	if ( var-> stage > csFrozen) return false;
2433 	if ( !set)
2434 		return var-> owner && ( PWidget( var-> owner)-> currentWidget == self);
2435 	o = ( PWidget) var-> owner;
2436 	if ( o == NULL) return false;
2437 	if ( current)
2438 		o-> self-> set_currentWidget( var-> owner, self);
2439 	else
2440 		if ( o-> currentWidget == self)
2441 			o-> self-> set_currentWidget( var-> owner, NULL_HANDLE);
2442 	return current;
2443 }
2444 
2445 Handle
Widget_currentWidget(Handle self,Bool set,Handle widget)2446 Widget_currentWidget( Handle self, Bool set, Handle widget)
2447 {
2448 	enter_method;
2449 	if ( var-> stage > csFrozen) return NULL_HANDLE;
2450 	if ( !set)
2451 		return var-> currentWidget;
2452 	if ( widget) {
2453 		if ( !widget || ( PWidget( widget)-> stage > csFrozen) ||
2454 			( PWidget( widget)-> owner != self)
2455 		) return NULL_HANDLE;
2456 		var-> currentWidget = widget;
2457 	} else
2458 		var-> currentWidget = NULL_HANDLE;
2459 
2460 	/* adjust selection if we're in currently selected chain */
2461 	if ( my-> get_selected( self))
2462 		my-> set_selectedWidget( self, widget);
2463 	return NULL_HANDLE;
2464 }
2465 
2466 Point
Widget_cursorPos(Handle self,Bool set,Point cursorPos)2467 Widget_cursorPos( Handle self, Bool set, Point cursorPos)
2468 {
2469 	if ( !set)
2470 		return apc_cursor_get_pos( self);
2471 	apc_cursor_set_pos( self, cursorPos. x, cursorPos. y);
2472 	return cursorPos;
2473 }
2474 
2475 Point
Widget_cursorSize(Handle self,Bool set,Point cursorSize)2476 Widget_cursorSize( Handle self, Bool set, Point cursorSize)
2477 {
2478 	if ( !set)
2479 		return apc_cursor_get_size( self);
2480 	apc_cursor_set_size( self, cursorSize. x, cursorSize. y);
2481 	return cursorSize;
2482 }
2483 
2484 Bool
Widget_cursorVisible(Handle self,Bool set,Bool cursorVisible)2485 Widget_cursorVisible( Handle self, Bool set, Bool cursorVisible)
2486 {
2487 	if ( !set)
2488 		return apc_cursor_get_visible( self);
2489 	return apc_cursor_set_visible( self, cursorVisible);
2490 }
2491 
2492 SV *
Widget_dndAware(Handle self,Bool set,SV * dndAware)2493 Widget_dndAware( Handle self, Bool set, SV * dndAware)
2494 {
2495 	if ( !set) {
2496 		if ( var->dndAware == NULL)
2497 			return &PL_sv_undef;
2498 		else if ( strcmp(var->dndAware, "1") == 0)
2499 			return newSViv(1);
2500 		else
2501 			return newSVpv(var->dndAware, 0);
2502 	} else if ( var->dndAware == NULL && SvBOOL(dndAware)) {
2503 		if ( apc_dnd_set_aware( self, true))
2504 			var-> dndAware = duplicate_string( SvPV_nolen( dndAware));
2505 	} else if ( var->dndAware != NULL ) {
2506 		free(var-> dndAware);
2507 		if ( !SvBOOL(dndAware)) {
2508 			var->dndAware = NULL;
2509 			apc_dnd_set_aware( self, false);
2510 		} else
2511 			var-> dndAware = duplicate_string( SvPV_nolen( dndAware));
2512 	}
2513 	return &PL_sv_undef;
2514 }
2515 
2516 Bool
Widget_enabled(Handle self,Bool set,Bool enabled)2517 Widget_enabled( Handle self, Bool set, Bool enabled)
2518 {
2519 	if ( !set) return apc_widget_is_enabled( self);
2520 	if ( !apc_widget_set_enabled( self, enabled))
2521 		return false;
2522 	if ( is_opt( optAutoEnableChildren))
2523 		CWidget(self)-> first_that( self, (void*)auto_enable_children, INT2PTR(void*,enabled));
2524 	return true;
2525 }
2526 
2527 Bool
Widget_firstClick(Handle self,Bool set,Bool firstClick)2528 Widget_firstClick( Handle self, Bool set, Bool firstClick)
2529 {
2530 	return set ?
2531 		apc_widget_set_first_click( self, firstClick) :
2532 		apc_widget_get_first_click( self);
2533 }
2534 
2535 Bool
Widget_focused(Handle self,Bool set,Bool focused)2536 Widget_focused( Handle self, Bool set, Bool focused)
2537 {
2538 	enter_method;
2539 	if ( var-> stage > csNormal) return false;
2540 	if ( !set)
2541 		return apc_widget_is_focused( self);
2542 
2543 	if ( focused) {
2544 		PWidget x = ( PWidget)( var-> owner);
2545 		Handle current = self;
2546 		while ( x) {
2547 			x-> currentWidget = current;
2548 			current = ( Handle) x;
2549 			x = ( PWidget) x-> owner;
2550 		}
2551 		var-> currentWidget = NULL_HANDLE;
2552 		if ( var-> stage == csNormal)
2553 			apc_widget_set_focused( self);
2554 	} else
2555 		if ( var-> stage == csNormal && my-> get_selected( self))
2556 			apc_widget_set_focused( NULL_HANDLE);
2557 	return focused;
2558 }
2559 
2560 SV *
Widget_helpContext(Handle self,Bool set,SV * helpContext)2561 Widget_helpContext( Handle self, Bool set, SV *helpContext)
2562 {
2563 	if ( set) {
2564 		if ( var-> stage > csFrozen) return NULL_SV;
2565 		free( var-> helpContext);
2566 		var-> helpContext = NULL;
2567 		var-> helpContext = duplicate_string( SvPV_nolen( helpContext));
2568 		opt_assign( optUTF8_helpContext, prima_is_utf8_sv(helpContext));
2569 	} else {
2570 		helpContext = newSVpv( var-> helpContext ? var-> helpContext : "", 0);
2571 		if ( is_opt( optUTF8_helpContext)) SvUTF8_on( helpContext);
2572 		return helpContext;
2573 	}
2574 	return NULL_SV;
2575 }
2576 
2577 SV *
Widget_get_hint(Handle self)2578 Widget_get_hint( Handle self)
2579 {
2580 	return newSVsv(var->hint);
2581 }
2582 
2583 void
Widget_set_hint(Handle self,SV * hint)2584 Widget_set_hint( Handle self, SV *hint)
2585 {
2586 	enter_method;
2587 	if ( var-> stage > csFrozen) return;
2588 	my-> first_that( self, (void*)hint_notify, (void*)hint);
2589 	if ( var-> hint ) sv_free( var-> hint );
2590 	var-> hint = newSVsv( hint);
2591 	if ( application && (( PApplication) application)-> hintVisible &&
2592 		(( PApplication) application)-> hintUnder == self)
2593 	{
2594 		Handle hintWidget = (( PApplication) application)-> hintWidget;
2595 		if ( SvLEN( var-> hint) == 0)
2596 			my-> set_hintVisible( self, 0);
2597 		if ( hintWidget)
2598 			CWidget(hintWidget)-> set_text( hintWidget, my-> get_hint( self));
2599 	}
2600 	opt_clear( optOwnerHint);
2601 }
2602 
2603 Bool
Widget_layered(Handle self,Bool set,Bool layered)2604 Widget_layered( Handle self, Bool set, Bool layered)
2605 {
2606 	HV * profile;
2607 	enter_method;
2608 	if ( !set)
2609 		return apc_widget_get_layered_request( self);
2610 	profile = newHV();
2611 	pset_i( layered, layered);
2612 	my-> set( self, profile);
2613 	sv_free(( SV *) profile);
2614 	return false;
2615 }
2616 
2617 int
Widget_left(Handle self,Bool set,int left)2618 Widget_left( Handle self, Bool set, int left)
2619 {
2620 	enter_method;
2621 	Point p = my-> get_origin( self);
2622 	if ( !set)
2623 		return p. x;
2624 	p. x = left;
2625 	my-> set_origin( self, p);
2626 	return 0;
2627 }
2628 
2629 Point
Widget_origin(Handle self,Bool set,Point origin)2630 Widget_origin( Handle self, Bool set, Point origin)
2631 {
2632 	if ( !set)
2633 		return apc_widget_get_pos( self);
2634 	apc_widget_set_pos( self, origin.x, origin.y);
2635 	return origin;
2636 }
2637 
2638 Bool
Widget_ownerBackColor(Handle self,Bool set,Bool ownerBackColor)2639 Widget_ownerBackColor( Handle self, Bool set, Bool ownerBackColor)
2640 {
2641 	enter_method;
2642 	if ( !set)
2643 		return is_opt( optOwnerBackColor);
2644 	opt_assign( optOwnerBackColor, ownerBackColor);
2645 	if ( is_opt( optOwnerBackColor) && var-> owner)
2646 	{
2647 		my-> set_backColor( self, ((( PWidget) var-> owner)-> self)-> get_backColor( var-> owner));
2648 		opt_set( optOwnerBackColor);
2649 		my-> repaint ( self);
2650 	}
2651 	return false;
2652 }
2653 
2654 Bool
Widget_ownerColor(Handle self,Bool set,Bool ownerColor)2655 Widget_ownerColor( Handle self, Bool set, Bool ownerColor)
2656 {
2657 	enter_method;
2658 	if ( !set)
2659 		return is_opt( optOwnerColor);
2660 	opt_assign( optOwnerColor, ownerColor);
2661 	if ( is_opt( optOwnerColor) && var-> owner)
2662 	{
2663 		my-> set_color( self, ((( PWidget) var-> owner)-> self)-> get_color( var-> owner));
2664 		opt_set( optOwnerColor);
2665 		my-> repaint( self);
2666 	}
2667 	return false;
2668 }
2669 
2670 Bool
Widget_ownerFont(Handle self,Bool set,Bool ownerFont)2671 Widget_ownerFont( Handle self, Bool set, Bool ownerFont )
2672 {
2673 	enter_method;
2674 	if ( !set)
2675 		return is_opt( optOwnerFont);
2676 	opt_assign( optOwnerFont, ownerFont);
2677 	if ( is_opt( optOwnerFont) && var-> owner)
2678 	{
2679 		my-> set_font ( self, ((( PWidget) var-> owner)-> self)-> get_font ( var-> owner));
2680 		opt_set( optOwnerFont);
2681 		my-> repaint ( self);
2682 	}
2683 	return false;
2684 }
2685 
2686 Bool
Widget_ownerHint(Handle self,Bool set,Bool ownerHint)2687 Widget_ownerHint( Handle self, Bool set, Bool ownerHint )
2688 {
2689 	enter_method;
2690 	if ( !set)
2691 		return is_opt( optOwnerHint);
2692 	opt_assign( optOwnerHint, ownerHint);
2693 	if ( is_opt( optOwnerHint) && var-> owner)
2694 	{
2695 		my-> set_hint( self, ((( PWidget) var-> owner)-> self)-> get_hint ( var-> owner));
2696 		opt_set( optOwnerHint);
2697 	}
2698 	return false;
2699 }
2700 
2701 Bool
Widget_ownerPalette(Handle self,Bool set,Bool ownerPalette)2702 Widget_ownerPalette( Handle self, Bool set, Bool ownerPalette)
2703 {
2704 	enter_method;
2705 	if ( !set)
2706 		return is_opt( optOwnerPalette);
2707 	if ( ownerPalette) my-> set_palette( self, NULL_SV);
2708 	opt_assign( optOwnerPalette, ownerPalette);
2709 	return false;
2710 }
2711 
2712 Bool
Widget_ownerShowHint(Handle self,Bool set,Bool ownerShowHint)2713 Widget_ownerShowHint( Handle self, Bool set, Bool ownerShowHint )
2714 {
2715 	enter_method;
2716 	if ( !set)
2717 		return is_opt( optOwnerShowHint);
2718 	opt_assign( optOwnerShowHint, ownerShowHint);
2719 	if ( is_opt( optOwnerShowHint) && var-> owner)
2720 	{
2721 		my-> set_showHint( self, CWidget( var-> owner)-> get_showHint ( var-> owner));
2722 		opt_set( optOwnerShowHint);
2723 	}
2724 	return false;
2725 }
2726 
2727 SV *
Widget_palette(Handle self,Bool set,SV * palette)2728 Widget_palette( Handle self, Bool set, SV * palette)
2729 {
2730 	int colors;
2731 	if ( !set)
2732 		return inherited-> palette( self, set, palette);
2733 
2734 	if ( var-> stage > csFrozen) return NULL_SV;
2735 	if ( var-> handle == NULL_HANDLE) return NULL_SV; /* aware of call from Drawable::init */
2736 
2737 	colors = var-> palSize;
2738 	free( var-> palette);
2739 	var-> palette = prima_read_palette( &var-> palSize, palette);
2740 	opt_clear( optOwnerPalette);
2741 	if ( colors == 0 && var-> palSize == 0)
2742 		return NULL_SV; /* do not bother apc */
2743 	if ( opt_InPaint)
2744 		apc_gp_set_palette( self);
2745 	else
2746 		apc_widget_set_palette( self);
2747 	return NULL_SV;
2748 }
2749 
2750 Handle
Widget_pointerIcon(Handle self,Bool set,Handle icon)2751 Widget_pointerIcon( Handle self, Bool set, Handle icon)
2752 {
2753 	enter_method;
2754 	Point hotSpot;
2755 
2756 	if ( var-> stage > csFrozen) return NULL_HANDLE;
2757 
2758 	if ( !set) {
2759 		HV * profile = newHV();
2760 		Handle icon = Object_create( "Prima::Icon", profile);
2761 		sv_free(( SV *) profile);
2762 		apc_pointer_get_bitmap( self, icon);
2763 		--SvREFCNT( SvRV((( PAnyObject) icon)-> mate));
2764 		return icon;
2765 	}
2766 
2767 	if ( icon != NULL_HANDLE && !kind_of( icon, CIcon)) {
2768 		warn("Illegal object reference passed to Widget::pointerIcon");
2769 		return NULL_HANDLE;
2770 	}
2771 	hotSpot = my-> get_pointerHotSpot( self);
2772 	apc_pointer_set_user( self, icon, hotSpot);
2773 	if ( var-> pointerType == crUser) my-> first_that( self, (void*)sptr, NULL);
2774 	return NULL_HANDLE;
2775 }
2776 
2777 Point
Widget_pointerHotSpot(Handle self,Bool set,Point hotSpot)2778 Widget_pointerHotSpot( Handle self, Bool set, Point hotSpot)
2779 {
2780 	enter_method;
2781 	Handle icon;
2782 	if ( !set)
2783 		return apc_pointer_get_hot_spot( self);
2784 	if ( var-> stage > csFrozen) return hotSpot;
2785 	icon = my-> get_pointerIcon( self);
2786 	apc_pointer_set_user( self, icon, hotSpot);
2787 	if ( var-> pointerType == crUser) my-> first_that( self, (void*)sptr, NULL);
2788 	return hotSpot;
2789 }
2790 
2791 int
Widget_pointerType(Handle self,Bool set,int type)2792 Widget_pointerType( Handle self, Bool set, int type)
2793 {
2794 	enter_method;
2795 	if ( var-> stage > csFrozen) return 0;
2796 	if ( !set)
2797 		return var-> pointerType;
2798 	var-> pointerType = type;
2799 	apc_pointer_set_shape( self, type);
2800 	my-> first_that( self, (void*)sptr, NULL);
2801 	return type;
2802 }
2803 
2804 Point
Widget_pointerPos(Handle self,Bool set,Point p)2805 Widget_pointerPos( Handle self, Bool set, Point p)
2806 {
2807 	if ( !set) {
2808 		p = apc_pointer_get_pos( self);
2809 		apc_widget_map_points( self, false, 1, &p);
2810 		return p;
2811 	}
2812 	apc_widget_map_points( self, true, 1, &p);
2813 	apc_pointer_set_pos( self, p. x, p. y);
2814 	return p;
2815 }
2816 
2817 Handle
Widget_popup(Handle self,Bool set,Handle popup)2818 Widget_popup( Handle self, Bool set, Handle popup)
2819 {
2820 	if ( var-> stage > csFrozen) return NULL_HANDLE;
2821 	if ( !set)
2822 		return var-> popupMenu;
2823 
2824 	if ( popup && !kind_of( popup, CPopup)) return NULL_HANDLE;
2825 	if ( var->popupMenu ) unprotect_object(var-> popupMenu);
2826 	var-> popupMenu = popup;
2827 	if ( var->popupMenu ) protect_object(var-> popupMenu);
2828 	return NULL_HANDLE;
2829 }
2830 
2831 Color
Widget_popupColorIndex(Handle self,Bool set,int index,Color color)2832 Widget_popupColorIndex( Handle self, Bool set, int index, Color color)
2833 {
2834 	if (( index < 0) || ( index > ciMaxId)) return clInvalid;
2835 	if ( !set)
2836 		return var-> popupColor[ index];
2837 	if ((( color & clSysFlag) != 0) && (( color & wcMask) == 0)) color |= wcPopup;
2838 	var-> popupColor[ index] = color;
2839 	return color;
2840 }
2841 
2842 SV *
Widget_popupItems(Handle self,Bool set,SV * popupItems)2843 Widget_popupItems( Handle self, Bool set, SV * popupItems)
2844 {
2845 	dPROFILE;
2846 	enter_method;
2847 	if ( var-> stage > csFrozen) return NULL_SV;
2848 	if ( !set)
2849 		return var-> popupMenu ?
2850 			CAbstractMenu( var-> popupMenu)-> get_items( var-> popupMenu, "", true) : NULL_SV;
2851 
2852 	if ( var-> popupMenu == NULL_HANDLE) {
2853 		if ( SvTYPE( popupItems)) {
2854 			HV * profile = newHV();
2855 			pset_sv( items, popupItems);
2856 			pset_H ( owner, self);
2857 			my-> set_popup( self, create_instance( "Prima::Popup"));
2858 			sv_free(( SV *) profile);
2859 		}
2860 	}
2861 	else
2862 		CAbstractMenu(var-> popupMenu)-> set_items(var-> popupMenu, popupItems);
2863 	return popupItems;
2864 }
2865 
2866 
2867 Rect
Widget_rect(Handle self,Bool set,Rect r)2868 Widget_rect( Handle self, Bool set, Rect r)
2869 {
2870 	enter_method;
2871 	if ( !set) {
2872 		Point p   = my-> get_origin( self);
2873 		Point s   = my-> get_size( self);
2874 		r. left   = p. x;
2875 		r. bottom = p. y;
2876 		r. right  = p. x + s. x;
2877 		r. top    = p. y + s. y;
2878 	} else
2879 		apc_widget_set_rect( self, r. left, r. bottom, r. right - r. left, r. top - r. bottom);
2880 	return r;
2881 }
2882 
2883 int
Widget_right(Handle self,Bool set,int right)2884 Widget_right( Handle self, Bool set, int right)
2885 {
2886 	enter_method;
2887 	Point p;
2888 	Rect r = my-> get_rect( self);
2889 	if ( !set)
2890 		return r. right;
2891 	p. x = r. left - r. right + right;
2892 	p. y = r. bottom;
2893 	my-> set_origin( self, p);
2894 	return 0;
2895 }
2896 
2897 Bool
Widget_scaleChildren(Handle self,Bool set,Bool scaleChildren)2898 Widget_scaleChildren( Handle self, Bool set, Bool scaleChildren)
2899 {
2900 	if ( !set)
2901 		return is_opt( optScaleChildren);
2902 	opt_assign( optScaleChildren, scaleChildren);
2903 	return false;
2904 }
2905 
2906 Bool
Widget_selectable(Handle self,Bool set,Bool selectable)2907 Widget_selectable( Handle self, Bool set, Bool selectable)
2908 {
2909 	if ( !set)
2910 		return is_opt( optSelectable);
2911 	opt_assign( optSelectable, selectable);
2912 	return false;
2913 }
2914 
2915 Bool
Widget_selected(Handle self,Bool set,Bool selected)2916 Widget_selected( Handle self, Bool set, Bool selected)
2917 {
2918 	enter_method;
2919 	if ( !set)
2920 		return my-> get_selectedWidget( self) != NULL_HANDLE;
2921 
2922 	if ( var-> stage > csFrozen) return selected;
2923 	if ( selected) {
2924 		if ( is_opt( optSelectable) && !is_opt( optSystemSelectable)) {
2925 			my-> set_focused( self, true);
2926 		} else
2927 		if ( var-> currentWidget) {
2928 			PWidget w = ( PWidget) var-> currentWidget;
2929 			if ( w-> options. optSystemSelectable && !w-> self-> get_clipOwner(( Handle) w))
2930 				w-> self-> bring_to_front(( Handle) w); /* <- very uncertain !!!! */
2931 			else
2932 				w-> self-> set_selected(( Handle) w, true);
2933 		} else
2934 		if ( is_opt( optSystemSelectable)) {
2935 			/* nothing to do with Widget, reserved for Window */
2936 		}
2937 		else {
2938 			PWidget toFocus = ( PWidget) find_tabfoc( self);
2939 			if ( toFocus)
2940 				toFocus-> self-> set_selected(( Handle) toFocus, 1);
2941 			else {
2942 			/* if group has no selectable widgets and cannot be selected by itself, */
2943 			/* process chain of bring_to_front(), followed by set_focused(1) call, if available */
2944 				PWidget x = ( PWidget) var-> owner;
2945 				List  lst;
2946 				int i;
2947 
2948 				list_create( &lst, 8, 8);
2949 				while ( x) {
2950 					if ( !toFocus && x-> options. optSelectable) {
2951 						toFocus = x;  /* choose closest owner to focus */
2952 						break;
2953 					}
2954 					if (( Handle) x != application && !kind_of(( Handle) x, CWindow))
2955 						list_insert_at( &lst, ( Handle) x, 0);
2956 					x = ( PWidget) x-> owner;
2957 				}
2958 
2959 				if ( toFocus)
2960 					toFocus-> self-> set_focused(( Handle) toFocus, 1);
2961 
2962 				for ( i = 0; i < lst. count; i++) {
2963 					PWidget v = ( PWidget) list_at( &lst, i);
2964 					v-> self-> bring_to_front(( Handle) v);
2965 				}
2966 				list_destroy( &lst);
2967 			}
2968 		} /* end set_selected( true); */
2969 	} else
2970 		my-> set_focused( self, false);
2971 	return selected;
2972 }
2973 
2974 Handle
Widget_selectedWidget(Handle self,Bool set,Handle widget)2975 Widget_selectedWidget( Handle self, Bool set, Handle widget)
2976 {
2977 	if ( var-> stage > csFrozen) return NULL_HANDLE;
2978 
2979 	if ( !set) {
2980 		if ( var-> stage <= csNormal) {
2981 			Handle foc = apc_widget_get_focused();
2982 			PWidget  f = ( PWidget) foc;
2983 			while( f) {
2984 				if (( Handle) f == self) return foc;
2985 				f = ( PWidget) f-> owner;
2986 			}
2987 		}
2988 		return NULL_HANDLE;
2989 
2990 		/* classic solution should be recursive and inheritant call */
2991 		/* of get_selected() here, when Widget would return state of */
2992 		/* child-group selected state until Widget::selected() called; */
2993 		/* thus, each of them would call apc_widget_get_focused - that's expensive, */
2994 		/* so that's the reason not to use classic object model here. */
2995 	}
2996 
2997 	if ( widget) {
2998 		if ( PWidget( widget)-> owner == self)
2999 			CWidget( widget)-> set_selected( widget, true);
3000 	} else {
3001 		/* give selection up to hierarchy chain */
3002 		Handle s = self;
3003 		while ( s) {
3004 			if ( CWidget( s)-> get_selectable( s)) {
3005 				CWidget( s)-> set_selected( s, true);
3006 				break;
3007 			}
3008 			s = PWidget( s)-> owner;
3009 		}
3010 	}
3011 	return NULL_HANDLE;
3012 }
3013 
3014 int
Widget_selectingButtons(Handle self,Bool set,int sb)3015 Widget_selectingButtons( Handle self, Bool set, int sb)
3016 {
3017 	if ( !set)
3018 		return var-> selectingButtons;
3019 	return var-> selectingButtons = sb;
3020 }
3021 
3022 Handle
Widget_shape(Handle self,Bool set,Handle mask)3023 Widget_shape( Handle self, Bool set, Handle mask)
3024 {
3025 	if ( var-> stage > csFrozen) return NULL_HANDLE;
3026 
3027 	if ( !set) {
3028 		if ( apc_widget_get_shape( self, NULL_HANDLE)) {
3029 			HV * profile = newHV();
3030 			Handle i = Object_create( "Prima::Region", profile);
3031 			sv_free(( SV *) profile);
3032 			apc_widget_get_shape( self, i);
3033 			--SvREFCNT( SvRV((( PAnyObject) i)-> mate));
3034 			return i;
3035 		} else
3036 			return NULL_HANDLE;
3037 	}
3038 
3039 	if ( mask && kind_of( mask, CRegion)) {
3040 		apc_widget_set_shape( self, mask);
3041 		return NULL_HANDLE;
3042 	}
3043 
3044 	if ( mask && !kind_of( mask, CImage)) {
3045 		warn("Illegal object reference passed to Drawable::region");
3046 		return NULL_HANDLE;
3047 	}
3048 
3049 	if ( mask ) {
3050 		Handle region;
3051 		HV * profile = newHV();
3052 
3053 		pset_H( image, mask );
3054 		region = Object_create("Prima::Region", profile);
3055 		sv_free(( SV *) profile);
3056 
3057 		apc_widget_set_shape( self, region);
3058 		Object_destroy(region);
3059 	} else
3060 		apc_widget_set_shape( self, NULL_HANDLE);
3061 
3062 	return NULL_HANDLE;
3063 }
3064 
3065 Bool
Widget_showHint(Handle self,Bool set,Bool showHint)3066 Widget_showHint( Handle self, Bool set, Bool showHint )
3067 {
3068 	enter_method;
3069 	Bool oldShowHint = is_opt( optShowHint);
3070 	if ( !set)
3071 		return oldShowHint;
3072 	my-> first_that( self, (void*)showhint_notify, &showHint);
3073 	opt_clear( optOwnerShowHint);
3074 	opt_assign( optShowHint, showHint);
3075 	if ( application && !is_opt( optShowHint) && oldShowHint) my-> set_hintVisible( self, 0);
3076 	return false;
3077 }
3078 
3079 Point
Widget_size(Handle self,Bool set,Point size)3080 Widget_size( Handle self, Bool set, Point size)
3081 {
3082 	if ( !set)
3083 		return apc_widget_get_size( self);
3084 	apc_widget_set_size( self, size.x, size.y);
3085 	return size;
3086 }
3087 
3088 Bool
Widget_syncPaint(Handle self,Bool set,Bool syncPaint)3089 Widget_syncPaint( Handle self, Bool set, Bool syncPaint)
3090 {
3091 	HV * profile;
3092 	enter_method;
3093 	if ( !set)
3094 		return apc_widget_get_sync_paint( self);
3095 	profile = newHV();
3096 	pset_i( syncPaint, syncPaint);
3097 	my-> set( self, profile);
3098 	sv_free(( SV *) profile);
3099 	return false;
3100 }
3101 
3102 int
Widget_tabOrder(Handle self,Bool set,int tabOrder)3103 Widget_tabOrder( Handle self, Bool set, int tabOrder)
3104 {
3105 	int count;
3106 	PWidget owner;
3107 
3108 	if ( var-> stage > csFrozen) return 0;
3109 	if ( !set)
3110 		return var-> tabOrder;
3111 
3112 	owner = ( PWidget) var-> owner;
3113 	count = owner-> widgets. count;
3114 	if ( tabOrder < 0) {
3115 		int i, maxOrder = -1;
3116 		/* finding maximal tabOrder value among the siblings */
3117 		for ( i = 0; i < count; i++) {
3118 			PWidget ctrl = ( PWidget) owner-> widgets. items[ i];
3119 			if ( self == ( Handle) ctrl) continue;
3120 			if ( maxOrder < ctrl-> tabOrder) maxOrder = ctrl-> tabOrder;
3121 		}
3122 		if ( maxOrder < INT_MAX) {
3123 			var-> tabOrder = maxOrder + 1;
3124 			return 0;
3125 		}
3126 		/* maximal value found, but has no use; finding gaps */
3127 		{
3128 			int j = 0;
3129 			Bool match = 1;
3130 			while ( !match) {
3131 				for ( i = 0; i < count; i++) {
3132 					PWidget ctrl = ( PWidget) owner-> widgets. items[ i];
3133 					if ( self == ( Handle) ctrl) continue;
3134 					if ( ctrl-> tabOrder == j) {
3135 						match = 1;
3136 						break;
3137 					}
3138 				}
3139 				j++;
3140 			}
3141 			var-> tabOrder = j - 1;
3142 		}
3143 	} else {
3144 		int i;
3145 		Bool match = 0;
3146 		/* finding exact match among the siblings */
3147 		for ( i = 0; i < count; i++) {
3148 			PWidget ctrl = ( PWidget) owner-> widgets. items[ i];
3149 			if ( self == ( Handle) ctrl) continue;
3150 			if ( ctrl-> tabOrder == tabOrder) {
3151 				match = 1;
3152 				break;
3153 			}
3154 		}
3155 		if ( match)
3156 			/* incrementing all tabOrders that greater than ours */
3157 			for ( i = 0; i < count; i++) {
3158 				PWidget ctrl = ( PWidget) owner-> widgets. items[ i];
3159 				if ( self == ( Handle) ctrl) continue;
3160 				if ( ctrl-> tabOrder >= tabOrder) ctrl-> tabOrder++;
3161 			}
3162 		var-> tabOrder = tabOrder;
3163 	}
3164 	return 0;
3165 }
3166 
3167 Bool
Widget_tabStop(Handle self,Bool set,Bool stop)3168 Widget_tabStop( Handle self, Bool set, Bool stop)
3169 {
3170 	if ( !set)
3171 		return is_opt( optTabStop);
3172 	opt_assign( optTabStop, stop);
3173 	return false;
3174 }
3175 
3176 Bool
Widget_transparent(Handle self,Bool set,Bool transparent)3177 Widget_transparent( Handle self, Bool set, Bool transparent)
3178 {
3179 	HV * profile;
3180 	enter_method;
3181 	if ( !set)
3182 		return apc_widget_get_transparent( self);
3183 	profile = newHV();
3184 	pset_i( transparent, transparent);
3185 	my-> set( self, profile);
3186 	sv_free(( SV *) profile);
3187 	return false;
3188 }
3189 
3190 SV *
Widget_get_text(Handle self)3191 Widget_get_text( Handle self)
3192 {
3193 	return newSVsv(var->text);
3194 }
3195 
3196 void
Widget_set_text(Handle self,SV * text)3197 Widget_set_text( Handle self, SV *text)
3198 {
3199 	if ( var-> stage > csFrozen) return;
3200 	if ( var-> text ) sv_free( var-> text );
3201 	var-> text = newSVsv(text);
3202 }
3203 
3204 int
Widget_top(Handle self,Bool set,int top)3205 Widget_top( Handle self, Bool set, int top)
3206 {
3207 	enter_method;
3208 	Point p;
3209 	Rect  r   = my-> get_rect( self);
3210 	if ( !set)
3211 		return r. top;
3212 	p. x = r. left;
3213 	p. y = r. bottom - r. top + top;
3214 	my-> set_origin( self, p);
3215 	return 0;
3216 }
3217 
3218 Bool
Widget_visible(Handle self,Bool set,Bool visible)3219 Widget_visible( Handle self, Bool set, Bool visible)
3220 {
3221 	return set ?
3222 		apc_widget_set_visible( self, visible) :
3223 		apc_widget_is_visible( self);
3224 }
3225 
3226 int
Widget_widgetClass(Handle self,Bool set,int widgetClass)3227 Widget_widgetClass( Handle self, Bool set, int widgetClass)
3228 {
3229 	enter_method;
3230 	if ( !set)
3231 		return var-> widgetClass;
3232 	var-> widgetClass = widgetClass;
3233 	my-> repaint( self);
3234 	return 0;
3235 }
3236 
3237 /* XS section */
XS(Widget_client_to_screen_FROMPERL)3238 XS( Widget_client_to_screen_FROMPERL)
3239 {
3240 	dXSARGS;
3241 	Handle self;
3242 	int i, count;
3243 	Point * points;
3244 
3245 	if (( items % 2) != 1)
3246 		croak ("Invalid usage of Widget::client_to_screen");
3247 	SP -= items;
3248 	self = gimme_the_mate( ST( 0));
3249 	if ( self == NULL_HANDLE)
3250 		croak( "Illegal object reference passed to Widget::client_to_screen");
3251 	count  = ( items - 1) / 2;
3252 	if ( !( points = allocn( Point, count))) {
3253 		PUTBACK;
3254 		return;
3255 	}
3256 	for ( i = 0; i < count; i++) {
3257 		points[i]. x = SvIV( ST( i * 2 + 1));
3258 		points[i]. y = SvIV( ST( i * 2 + 2));
3259 	}
3260 	apc_widget_map_points( self, true, count, points);
3261 	EXTEND( sp, count * 2);
3262 	for ( i = 0; i < count; i++) {
3263 		PUSHs( sv_2mortal( newSViv( points[i].x)));
3264 		PUSHs( sv_2mortal( newSViv( points[i].y)));
3265 	}
3266 	PUTBACK;
3267 	free( points);
3268 	return;
3269 }
3270 
XS(Widget_screen_to_client_FROMPERL)3271 XS( Widget_screen_to_client_FROMPERL)
3272 {
3273 	dXSARGS;
3274 	Handle self;
3275 	int i, count;
3276 	Point * points;
3277 
3278 	if (( items % 2) != 1)
3279 		croak ("Invalid usage of Widget::screen_to_client");
3280 	SP -= items;
3281 	self = gimme_the_mate( ST( 0));
3282 	if ( self == NULL_HANDLE)
3283 		croak( "Illegal object reference passed to Widget::screen_to_client");
3284 	count  = ( items - 1) / 2;
3285 	if ( !( points = allocn( Point, count))) {
3286 		PUTBACK;
3287 		return;
3288 	}
3289 	for ( i = 0; i < count; i++) {
3290 		points[i]. x = SvIV( ST( i * 2 + 1));
3291 		points[i]. y = SvIV( ST( i * 2 + 2));
3292 	}
3293 	apc_widget_map_points( self, false, count, points);
3294 	EXTEND( sp, count * 2);
3295 	for ( i = 0; i < count; i++) {
3296 		PUSHs( sv_2mortal( newSViv( points[i].x)));
3297 		PUSHs( sv_2mortal( newSViv( points[i].y)));
3298 	}
3299 	PUTBACK;
3300 	free( points);
3301 	return;
3302 }
3303 
3304 
XS(Widget_get_widgets_FROMPERL)3305 XS( Widget_get_widgets_FROMPERL)
3306 {
3307 	dXSARGS;
3308 	Handle self;
3309 	Handle * list;
3310 	int i, count;
3311 
3312 	if ( items != 1)
3313 		croak ("Invalid usage of Widget.get_widgets");
3314 	SP -= items;
3315 	self = gimme_the_mate( ST( 0));
3316 	if ( self == NULL_HANDLE)
3317 		croak( "Illegal object reference passed to Widget.get_widgets");
3318 	count = var-> widgets. count;
3319 	list  = var-> widgets. items;
3320 	EXTEND( sp, count);
3321 	for ( i = 0; i < count; i++)
3322 		PUSHs( sv_2mortal( newSVsv((( PAnyObject) list[ i])-> mate)));
3323 	PUTBACK;
3324 	return;
3325 }
3326 
Widget_get_widgets(Handle self)3327 void Widget_get_widgets          ( Handle self) { warn("Invalid call of Widget::get_widgets"); }
Widget_get_widgets_REDEFINED(Handle self)3328 void Widget_get_widgets_REDEFINED( Handle self) { warn("Invalid call of Widget::get_widgets"); }
Widget_screen_to_client(Handle self)3329 void Widget_screen_to_client ( Handle self) { warn("Invalid call of Widget::screen_to_client"); }
Widget_screen_to_client_REDEFINED(Handle self)3330 void Widget_screen_to_client_REDEFINED ( Handle self) { warn("Invalid call of Widget::screen_to_client"); }
Widget_client_to_screen(Handle self)3331 void Widget_client_to_screen ( Handle self) { warn("Invalid call of Widget::screen_to_client"); }
Widget_client_to_screen_REDEFINED(Handle self)3332 void Widget_client_to_screen_REDEFINED ( Handle self) { warn("Invalid call of Widget::screen_to_client"); }
3333 
3334 #ifdef __cplusplus
3335 }
3336 #endif
3337