2 classvar <globalKeyDownAction, <globalKeyUpAction;
6 classvar <currentDrag, <currentDragString;
8 var wasRemoved = false;
10 var <font, <resize = 1, <alpha = 1.0;
12 var <decorator, <layout;
14 var <>userCanClose=true, <>deleteOnClose = true;
17 var <mouseDownAction, <mouseUpAction, <mouseEnterAction, <mouseLeaveAction;
18 var <mouseMoveAction, <mouseOverAction, <mouseWheelAction;
19 var <keyDownAction, <keyUpAction, <keyModifiersChangedAction;
22 var <focusGainedAction, <focusLostAction;
25 var <beginDragAction, <canReceiveDragHandler, <receiveDragHandler;
27 var <toFrontAction, <endFrontAction;
29 var <onClose, <onResize, <onMove;
31 *implementsClass { ^this.name.asString[1..].asSymbol }
34 hSizePolicy = [1,2,3,1,2,3,1,2,3];
35 vSizePolicy = [1,1,1,2,2,2,3,3,3];
38 *new { arg parent, bounds;
39 var p = parent.asView;
40 ^super.new( [p, bounds.asRect] ).initQView( p );
43 *newCustom { arg customArgs;
44 ^super.new( customArgs ).initQView( nil );
47 *qtClass { ^'QcDefaultWidget' }
53 ^this.primitiveFailed;
57 if( this.parent.notNil and: { this.parent.decorator.notNil } )
58 { this.parent.decorator.remove(this) };
61 this.children.do { |child| child.remove };
64 mapToGlobal { arg point;
66 ^this.primitiveFailed;
69 // ----------------- properties --------------------------
72 this.setProperty( \font, f );
75 toolTip { ^this.getProperty(\toolTip) }
76 toolTip_ { arg t; this.setProperty( \toolTip, t ) }
79 ^this.getProperty( \palette );
83 this.setProperty( \palette, p );
86 background { ^this.getProperty(\background); }
87 background_ { arg color; this.setProperty(\background, color); }
89 // NOTE: only for backwards compatibility
90 backColor_ { arg color;
91 this.background = color;
95 ^this.bounds.moveToPoint( this.mapToGlobal( 0@0 ) );
99 ^this.getProperty(\geometry)
103 this.setProperty(\geometry, rect.asRect )
106 sizeHint { ^this.getProperty(\sizeHint) }
108 minSizeHint { ^this.getProperty(\minimumSizeHint) }
110 // a Point can be passed instead of a Size
112 var max = QLimits(\maxWidgetSize);
114 this.setProperty( \maximumSize, Size( min(max,size.width), min(max,size.height) ) );
117 // a Point can be passed instead of a Size
118 minSize_ { arg size; this.setProperty( \minimumSize, size.asSize ); }
120 fixedSize_ { arg size;
122 this.setProperty( \minimumSize, size );
123 this.setProperty( \maximumSize, size );
126 fixedWidth_ { arg width;
127 this.setProperty( \minimumWidth, width );
128 this.setProperty( \maximumWidth, width );
131 fixedHeight_ { arg height;
132 this.setProperty( \minimumHeight, height );
133 this.setProperty( \maximumHeight, height );
136 maxWidth_ { arg width;
137 this.setProperty( \maximumWidth, min( width, QLimits(\maxWidgetSize) ) );
140 minWidth_ { arg width; this.setProperty( \minimumWidth, width ); }
142 maxHeight_ { arg height;
143 this.setProperty( \maximumHeight, min( height, QLimits(\maxWidgetSize) ) );
146 minHeight_ { arg height; this.setProperty( \minimumHeight, height ); }
148 // backwards compatibility
149 relativeOrigin { ^true }
152 this.bounds_( this.bounds.moveTo( x, y ) );
155 resizeTo { arg width, height;
156 this.bounds_( this.bounds.resizeTo( width, height ) );
160 ^this.getProperty(\visible)
163 this.setProperty(\visible, bool, false)
167 ^this.getProperty(\enabled)
170 this.setProperty(\enabled, bool)
174 this.setProperty(\_qc_hSizePolicy, hSizePolicy[anInt-1]);
175 this.setProperty(\_qc_vSizePolicy, vSizePolicy[anInt-1]);
180 var policy = this.getProperty(\focusPolicy);
184 canFocus_ { arg bool;
186 if( bool ) { policy = 16r1 | 16r2 | 16r8 } { policy = 0 };
187 this.setProperty(\focusPolicy, policy);
190 focus { arg flag=true;
192 ^this.primitiveFailed;
196 ^this.getProperty( \focus );
200 _QWidget_AcceptsMouse
201 ^this.primitiveFailed;
204 acceptsMouse_ { arg bool;
205 _QWidget_SetAcceptsMouse
206 ^this.primitiveFailed;
209 focusColor_ { arg color;
210 this.setProperty(\focusColor, color);
214 ^this.getProperty(\focusColor) ? Color();
217 // ------------------ container stuff ----------------------------
219 children { arg class = QView;
220 var ch = super.children( class );
221 ^ch.select { |v| (v.tryPerform(\isClosed) ? false).not };
224 parent { arg class = QView;
225 if (wasRemoved) { ^nil } { ^super.parent(class) };
231 if (wasRemoved.not) {
234 allParents = allParents.add( p );
246 var childWidgets = this.children( QView );
247 childWidgets.do { |child| child.remove };
250 layout_ { arg newLayout;
251 if( newLayout.notNil && (newLayout != layout) ) {
252 this.prSetLayout( newLayout );
257 addFlowLayout { arg margin, gap;
258 this.decorator_( FlowLayout( this.bounds.moveTo(0, 0), margin, gap ) );
262 decorator_ { arg decor;
263 decor.bounds = decor.bounds.moveTo(0, 0);
268 // ................. top window stuff ............................
271 ^this.getProperty( \windowTitle );
275 this.setProperty( \windowTitle, string );
280 ^this.primitiveFailed;
284 if( this.visible ) { this.invokeMethod( \showMinimized, synchronous:false ) };
288 if( this.getProperty( \minimized ) ) { this.invokeMethod( \showNormal, synchronous:false ) };
292 this.invokeMethod( \showFullScreen, synchronous:false );
296 if( this.getProperty( \fullScreen ) ) { this.invokeMethod( \showNormal, synchronous:false ) };
301 this.setProperty( \windowOpacity, aFloat );
305 _QWidget_GetAlwaysOnTop
306 ^this.primitiveFailed;
309 alwaysOnTop_ { arg boolean;
310 _QWidget_SetAlwaysOnTop
311 ^this.primitiveFailed;
317 { this.visible_( false ); }
321 if (wasRemoved) {^true} {^this.isValid.not};
324 notClosed { ^this.isClosed.not }
326 // TODO: deprecate acceptsMouseOver and expose 'mouseTracking' property directly
327 acceptsMouseOver { ^this.getProperty(\_qc_win_mouse_tracking) == true }
328 acceptsMouseOver_ { arg flag; this.setProperty(\_qc_win_mouse_tracking, flag == true) }
330 // ----------------- actions .....................................
333 // NOTE: not all widgets have action() signal
335 this.manageMethodConnection( action, func, 'action()', \doAction );
340 addAction { arg func, selector=\action;
341 this.perform(selector.asSetter, this.perform(selector).addFunc(func));
344 removeAction { arg func, selector=\action;
345 this.perform(selector.asSetter, this.perform(selector).removeFunc(func));
348 *globalKeyDownAction_ { arg action;
349 globalKeyDownAction = action;
350 this.setGlobalEventEnabled( 16r01 /* KeyPress */, true );
354 *globalKeyUpAction_ { arg action;
355 globalKeyUpAction = action;
356 this.setGlobalEventEnabled( 16r02 /* KeyRelease */, true );
359 keyDownAction_ { arg aFunction;
360 keyDownAction = aFunction;
361 this.setEventHandlerEnabled( QObject.keyDownEvent, true );
364 keyUpAction_ { arg aFunction;
365 keyUpAction = aFunction;
366 this.setEventHandlerEnabled( QObject.keyUpEvent, true );
369 keyModifiersChangedAction_ { arg aFunction;
370 keyModifiersChangedAction = aFunction;
371 this.setEventHandlerEnabled( QObject.keyDownEvent, true );
372 this.setEventHandlerEnabled( QObject.keyUpEvent, true );
375 mouseDownAction_ { arg aFunction;
376 mouseDownAction = aFunction;
377 this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true );
378 this.setEventHandler( QObject.mouseDblClickEvent, \mouseDownEvent, true );
381 mouseUpAction_ { arg aFunction;
382 mouseUpAction = aFunction;
383 this.setEventHandler( QObject.mouseUpEvent, \mouseUpEvent, true );
386 mouseMoveAction_ { arg aFunction;
387 mouseMoveAction = aFunction;
388 this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true );
391 // mouseOverAction responds to same Qt event as mouseMoveAction,
392 // but on different conditions.
393 // See QView:-mouseMoveEvent method.
394 mouseOverAction_ { arg aFunction;
395 mouseOverAction = aFunction;
396 this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true );
397 this.setProperty(\mouseTracking, true);
400 mouseEnterAction_ { arg aFunction;
401 mouseEnterAction = aFunction;
402 this.setEventHandler( QObject.mouseEnterEvent, \mouseEnterEvent, true );
405 mouseLeaveAction_ { arg aFunction;
406 mouseLeaveAction = aFunction;
407 this.setEventHandler( QObject.mouseLeaveEvent, \mouseLeaveEvent, true );
410 mouseWheelAction_ { arg aFunction;
411 mouseWheelAction = aFunction;
412 this.setEventHandler( QObject.mouseWheelEvent, \mouseWheelEvent, true );
415 beginDragAction_ { arg handler;
416 beginDragAction = handler;
417 this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true )
420 canReceiveDragHandler_ { arg handler;
421 canReceiveDragHandler = handler;
422 this.setDragEventsEnabled( true );
425 receiveDragHandler_ { arg handler;
426 receiveDragHandler = handler;
427 this.setDragEventsEnabled( true );
430 toFrontAction_ { arg aFunction;
431 toFrontAction = aFunction;
432 this.setEventHandler( QObject.windowActivateEvent,
433 \onWindowActivateEvent );
436 endFrontAction_ { arg aFunction;
437 endFrontAction = aFunction;
438 this.setEventHandler( QObject.windowDeactivateEvent,
439 \onWindowDeactivateEvent );
442 focusGainedAction_ { arg handler;
443 focusGainedAction = handler;
444 this.setEventHandler( 8 /* QEvent::FocusIn */, \focusInEvent );
447 focusLostAction_ { arg handler;
448 focusLostAction = handler;
449 this.setEventHandler( 9 /* QEvent::FocusOut */, \focusOutEvent );
452 onMove_ { arg aFunction;
454 this.setEventHandler( 13 /* QEvent::Move */, \moveEvent );
457 onResize_ { arg aFunction;
458 onResize = aFunction;
459 this.setEventHandler( 14 /* QEvent::Resize */, \resizeEvent );
463 this.manageFunctionConnection( onClose, func, 'destroyed()', false );
471 defaultKeyDownAction { arg char, modifiers, unicode, keycode, key; }
473 defaultKeyUpAction { arg char, modifiers, unicode, keycode, key; }
475 keyDown { arg char, modifiers, unicode, keycode, key;
476 if( keyDownAction.notNil ) {
477 ^keyDownAction.value( this, char, modifiers, unicode, keycode, key );
479 ^this.defaultKeyDownAction( char, modifiers, unicode, keycode, key );
483 keyUp { arg char, modifiers, unicode, keycode, key;
485 if( keyUpAction.notNil ) {
486 ^keyUpAction.value( this, char, modifiers, unicode, keycode, key );
488 ^this.defaultKeyUpAction( char, modifiers, unicode, keycode, key );
492 keyModifiersChanged { arg modifiers;
493 keyModifiersChangedAction.value( this, modifiers);
496 mouseDown { arg x, y, modifiers, buttonNumber, clickCount;
497 ^mouseDownAction.value( this, x, y, modifiers, buttonNumber, clickCount );
500 mouseUp { arg x, y, modifiers, buttonNumber;
501 ^mouseUpAction.value( this, x, y, modifiers, buttonNumber );
504 mouseMove { arg x, y, modifiers;
505 ^mouseMoveAction.value( this, x, y, modifiers );
508 mouseOver { arg x, y;
509 ^mouseOverAction.value( this, x, y );
513 ^mouseEnterAction.value(this);
517 ^mouseLeaveAction.value(this);
520 mouseWheel { arg x, y, modifiers, xDelta, yDelta;
521 ^mouseWheelAction.value( this, x, y, modifiers, xDelta, yDelta );
524 /* ---------------- private ----------------------- */
526 *prSetCurrentDrag { arg obj; currentDrag = obj; currentDragString = obj.asCompileString; }
527 *prClearCurrentDrag { currentDrag = nil; currentDragString = nil; }
529 *setGlobalEventEnabled { arg event, enabled;
530 _QWidget_SetGlobalEventEnabled
533 initQView { arg parent;
535 var handleKeyDown, handleKeyUp, overridesMouseDown, handleDrag;
538 if( parent.decorator.notNil ) { parent.decorator.place(this) }
541 this.setEventHandler( QObject.closeEvent, \onCloseEvent, true );
544 handleKeyDown = handleKeyUp = this.overrides( \keyModifiersChanged );
545 if( handleKeyDown.not )
546 { handleKeyDown = this.overrides( \defaultKeyDownAction ) };
547 if( handleKeyUp.not )
548 { handleKeyUp = this.overrides( \defaultKeyUpAction )};
550 this.setEventHandler( QObject.keyDownEvent, \keyDownEvent, true, enabled: handleKeyDown );
551 this.setEventHandler( QObject.keyUpEvent, \keyUpEvent, true, enabled: handleKeyUp );
554 overridesMouseDown = this.overrides( \mouseDown );
555 if( this.respondsTo(\defaultGetDrag) || overridesMouseDown )
556 {this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true )};
557 if( overridesMouseDown )
558 {this.setEventHandler( QObject.mouseDblClickEvent, \mouseDownEvent, true )};
559 if( this.overrides( \mouseUp ) )
560 {this.setEventHandler( QObject.mouseUpEvent, \mouseUpEvent, true )};
561 if( this.overrides( \mouseMove ) || this.overrides( \mouseOver ) )
562 {this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true )};
563 if( this.overrides( \mouseEnter ) )
564 {this.setEventHandler( QObject.mouseEnterEvent, \mouseEnterEvent, true )};
565 if( this.overrides( \mouseLeave ) )
566 {this.setEventHandler( QObject.mouseLeaveEvent, \mouseLeaveEvent, true )};
567 if( this.overrides( \mouseWheel ) )
568 {this.setEventHandler( QObject.mouseWheelEvent, \mouseWheelEvent, true )};
571 handleDrag = this.respondsTo(\defaultCanReceiveDrag) or: {this.respondsTo(\defaultReceiveDrag)};
572 this.setEventHandler( 60, \dragEnterEvent, true, enabled:handleDrag );
573 this.setEventHandler( 61, \dragMoveEvent, true, enabled:handleDrag );
574 this.setEventHandler( 63, \dropEvent, true, enabled:handleDrag );
578 if( userCanClose != false ) {
579 if( deleteOnClose != false ) { this.remove; ^true };
585 onWindowActivateEvent {
586 toFrontAction.value(this);
589 onWindowDeactivateEvent {
590 endFrontAction.value(this);
593 focusInEvent { focusGainedAction.value(this) }
594 focusOutEvent { focusLostAction.value(this) }
596 moveEvent { onMove.value(this) }
597 resizeEvent { onResize.value(this) }
599 keyDownEvent { arg char, modifiers, unicode, keycode, key, spontaneous;
600 modifiers = QKeyModifiers.toCocoa(modifiers);
603 // this event has never been propagated to parent yet
604 QView.globalKeyDownAction.value( this, char, modifiers, unicode, keycode, key );
607 if( (key == 16r1000020) || (key == 16r1000021) ||
608 (key == 16r1000022) || (key == 16r1000023 ) )
609 { this.keyModifiersChanged( modifiers ) };
611 ^this.keyDown( char, modifiers, unicode, keycode, key );
614 keyUpEvent { arg char, modifiers, unicode, keycode, key, spontaneous;
615 modifiers = QKeyModifiers.toCocoa(modifiers);
618 // this event has never been propagated to parent yet
619 QView.globalKeyUpAction.value( this, char, modifiers, unicode, keycode, key );
622 if( (key == 16r1000020) || (key == 16r1000021) ||
623 (key == 16r1000022) || (key == 16r1000023 ) )
624 { this.keyModifiersChanged( modifiers ) };
626 ^this.keyUp( char, modifiers, unicode, keycode, key );
629 mouseDownEvent { arg x, y, modifiers, buttonNumber, clickCount;
630 // WARNING: QDragView and QListView override this method!
632 if( (modifiers & QKeyModifiers.control) > 0 ) { // if Ctrl / Cmd mod
633 // Try to get drag obj and start a drag.
634 // If successful, block further processing of this event.
635 if( this.beginDrag( x, y ) ) { ^false };
638 // else continue to handle mouse down event
639 modifiers = QKeyModifiers.toCocoa(modifiers);
640 ^this.mouseDown( x, y, modifiers, buttonNumber, clickCount );
643 mouseUpEvent { arg x, y, modifiers, buttonNumber;
644 modifiers = QKeyModifiers.toCocoa(modifiers);
645 ^this.mouseUp( x, y, modifiers, buttonNumber );
648 mouseMoveEvent { arg x, y, modifiers, buttons;
650 modifiers = QKeyModifiers.toCocoa(modifiers);
651 ^this.mouseMove( x, y, modifiers );
653 ^this.mouseOver( x, y )
658 var dummy = 0; // prevent this method from being optimized away
663 var dummy = 0; // prevent this method from being optimized away
667 mouseWheelEvent { arg x, y, modifiers, xDelta, yDelta;
668 modifiers = QKeyModifiers.toCocoa(modifiers);
669 ^this.mouseWheel( x, y, modifiers, xDelta, yDelta );
672 beginDrag { arg x, y;
674 if( beginDragAction.notNil )
675 { obj = beginDragAction.value( this, x, y ) }
676 { obj = this.tryPerform( \defaultGetDrag, x, y ) };
678 QView.prSetCurrentDrag( obj );
680 this.prStartDrag( dragLabel ?? str, obj, str );
686 canReceiveDrag { arg x, y;
687 if( canReceiveDragHandler.notNil )
688 { ^this.canReceiveDragHandler.value( this, x, y ) }
689 { ^( this.tryPerform( \defaultCanReceiveDrag, x, y ) ? false ) };
692 receiveDrag { arg x, y;
693 if( receiveDragHandler.notNil )
694 { this.receiveDragHandler.value( this, x, y ) }
695 { this.tryPerform( \defaultReceiveDrag, x, y ) };
698 prStartDrag { arg label, data, dataAsString;
700 ^this.primitiveFailed;
703 dragEnterEvent { arg internal, data;
705 // dnd incoming from outside SC
706 QView.prSetCurrentDrag(data);
708 // always accept the event
712 dragMoveEvent { arg x, y;
713 // make sure the event is always consumed
714 ^this.canReceiveDrag( x, y ).switch (
721 dropEvent { arg x, y;
722 this.receiveDrag( x, y );
723 // always accept the event
727 setDragEventsEnabled { arg enabled;
728 this.setEventHandlerEnabled( 60, enabled );
729 this.setEventHandlerEnabled( 61, enabled );
730 this.setEventHandlerEnabled( 63, enabled );
733 prSetLayout { arg layout;
735 ^this.primitiveFailed;
738 manageMethodConnection { arg oldAction, newAction, signal, method, sync=false;
739 if( newAction !== oldAction ) {
741 { oldAction.isNil && newAction.notNil } {this.connectMethod (signal, method, sync)}
742 { oldAction.notNil && newAction.isNil } {this.disconnectMethod (signal, method)}
747 manageFunctionConnection { arg oldAction, newAction, signal, sync=false;
748 if( newAction !== oldAction ) {
749 if( oldAction.notNil ) {this.disconnectFunction (signal, oldAction)};
750 if( newAction.notNil ) {this.connectFunction (signal, newAction, sync)};
754 overrides { arg method; ^this.prOverrides(QView, method) }
756 prOverrides { arg superclass, method;
757 _Qt_IsMethodOverridden
758 ^this.primitiveFailed
761 nonimpl { arg methodName;
762 this.class.nonimpl( methodName );
765 *nonimpl { arg methodName;
766 this.debug( msg: methodName.asString ++ " is not implemented yet" )
769 *debug { arg level = 1, msg = "";
770 if( QtGUI.debugLevel >= level ) { ("Qt: " ++ this.asString ++ ": " ++ msg).postln }