1 // Written in the D programming language. 2 /++ 3 + Authors: KanzakiKino 4 + Copyright: KanzakiKino 2018 5 + License: LGPL-3.0 6 ++/ 7 module w4d.widget.mdi.window; 8 import w4d.event; 9 10 /// An enum of rectangle sides. 11 enum Side 12 { 13 None = 0b0000, 14 Left = 0b0001, 15 Top = 0b0010, 16 Right = 0b0100, 17 Bottom = 0b1000, 18 } 19 20 /// A handler that handles closing MdiClient. 21 alias MdiClientCloseHandler = EventHandler!( bool ); 22 23 /// A template that declares methods related to operating Window. 24 template WindowOperations () 25 { 26 protected uint _draggingSides; 27 28 protected void enableSideDragging ( vec2 pos ) 29 { 30 const lt = style.translate + 31 style.box.borderInsideLeftTop; 32 const ltsz = vec2( style.box.paddings.left.calced, 33 style.box.paddings.top.calced ); 34 35 const rb = lt + ltsz + style.box.clientSize; 36 const rbsz = vec2( style.box.paddings.right.calced, 37 style.box.paddings.bottom.calced ); 38 39 _draggingSides = Side.None; 40 if ( pos.x > lt.x && pos.x < lt.x+ltsz.x ) { 41 _draggingSides |= Side.Left; 42 } 43 if ( pos.y > lt.y && pos.y < lt.y+ltsz.y ) { 44 _draggingSides |= Side.Top; 45 } 46 if ( pos.x > rb.x && pos.x < rb.x+rbsz.x ) { 47 _draggingSides |= Side.Right; 48 } 49 if ( pos.y > rb.y && pos.y < rb.y+rbsz.y ) { 50 _draggingSides |= Side.Bottom; 51 } 52 } 53 54 protected void resizeWithDragging ( vec2 cur ) 55 { 56 const sides = _draggingSides; 57 auto size = _size, pos = _pos; 58 59 if ( sides & Side.Left ) { 60 size.x += pos.x-cur.x; 61 pos.x = cur.x; 62 } 63 if ( sides & Side.Top ) { 64 size.y += pos.y-cur.y; 65 pos.y = cur.y; 66 } 67 if ( sides & Side.Right ) { 68 size.x = cur.x - pos.x; 69 } 70 if ( sides & Side.Bottom ) { 71 size.y = cur.y - pos.y; 72 } 73 move ( pos ); 74 resize( size ); 75 } 76 77 78 protected vec2 _minSize; 79 @property minSize () { return _minSize; } 80 81 protected vec2 _maxSize; 82 @property maxSize () { return _maxSize; } 83 84 void limitSize ( vec2 min, vec2 max ) 85 { 86 _minSize = min; 87 _maxSize = max; 88 resize( size ); 89 } 90 91 92 protected vec2 _pos; 93 @property vec2 pos () { return _pos; } 94 95 protected vec2 _size; 96 @property vec2 size () { return _size; } 97 98 void move ( vec2 pos ) 99 { 100 _pos = pos; 101 requestLayout(); 102 } 103 void resize ( vec2 size ) 104 { 105 _size = size; 106 requestLayout(); 107 } 108 109 MdiClientCloseHandler onClose; // Return true to abort closing. 110 void close () 111 { 112 enforce( _host, "Host is not defined yet." ); 113 if ( !onClose.call() ) { 114 _host.removeClient( this ); 115 } 116 } 117 118 119 override @property const(Cursor) cursor () 120 { 121 return 122 _draggingSides & Side.Left ? Cursor.HResize: 123 _draggingSides & Side.Right ? Cursor.HResize: 124 _draggingSides & Side.Top ? Cursor.VResize: 125 _draggingSides & Side.Bottom? Cursor.VResize: 126 super.cursor; 127 } 128 129 override bool handleMouseMove ( vec2 cur ) 130 { 131 if ( super.handleMouseMove( cur ) ) return true; 132 133 if ( isTracked ) { 134 cur -= _host.style.clientLeftTop; 135 resizeWithDragging( cur ); 136 return true; 137 } 138 139 enableSideDragging( cur ); 140 return true; 141 } 142 143 override bool handleMouseButton ( MouseButton btn, bool status, vec2 pos ) 144 { 145 enforce( _host, "MdiHost is null." ); 146 _host.focusClient( this ); 147 148 if ( super.handleMouseButton(btn,status,pos) ) return true; 149 return false; 150 } 151 }