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.host;
8 import w4d.style.color,
9        w4d.style.widget,
10        w4d.task.window,
11        w4d.widget.mdi.layout,
12        w4d.widget.base,
13        w4d.exception;
14 import gl3n.linalg;
15 import std.algorithm,
16        std.array;
17 
18 /// A host widget for MDI.
19 class MdiHostWidget : Widget
20 {
21     protected MdiClient[] _clients;
22     /// Child clients.
23     @property clients () { return _clients; }
24 
25     ///
26     override @property Widget[] children ()
27     {
28         return _clients.map!"a.widget".array;
29     }
30 
31     ///
32     this ()
33     {
34         super();
35         setLayout!MdiLayout();
36 
37         _clients = [];
38     }
39 
40     /// Adds the client widget.
41     void addClient ( MdiClient cli )
42     {
43         enforce( cli, "The client is invalid." );
44         cli.setHost( this );
45         _clients ~= cli;
46         infectWindowContext();
47 
48         unfocusAllClients();
49         cli.widget.enableState( WidgetState.Focused );
50     }
51     /// Removes the client widget.
52     void removeClient ( MdiClient cli )
53     {
54         _context.forget( cli.widget );
55         _clients = _clients.remove!( x => x is cli );
56     }
57 
58     protected void unfocusAllClients ()
59     {
60         foreach ( cli; _clients ) {
61             cli.widget.disableState( WidgetState.Focused );
62         }
63     }
64     /// Focuses to the client.
65     void focusClient ( MdiClient cli )
66     {
67         enforce( cli, "The client is invalid." );
68         removeClient( cli );
69         addClient( cli );
70     }
71 
72     ///
73     override @property bool needLayout ()
74     {
75         return _needLayout;
76     }
77     /// Re-layouts child clients only that need layout.
78     void layoutQuickly ()
79     {
80         auto pos  = style.clientLeftTop;
81         auto size = style.box.clientSize;
82 
83         children.filter!"a.needLayout"().
84             each!( x => x.layout(pos,size) );
85     }
86 
87     ///
88     override void draw ( Window w, ColorSet parent )
89     {
90         layoutQuickly();
91 
92         auto leftTop = style.translate +
93             style.box.borderInsideLeftTop;
94 
95         w.clip.pushRect( leftTop,
96                 style.box.borderInsideSize );
97         super.draw( w, parent );
98         w.clip.popRect();
99     }
100 }
101 
102 /// An interface of clients for MDI..
103 interface MdiClient
104 {
105     /// Position of the client.
106     @property vec2 pos  ();
107     /// Size of the client.
108     @property vec2 size ();
109 
110     /// This property returns thiself that is casted to Widget.
111     /// To prove the casting is safe.
112     @property Widget widget ();
113 
114     /// Changes the host widget.
115     void setHost ( MdiHostWidget );
116 }