1 module theme.manager;
2 
3 import theme.layout;
4 import gui.font;
5 import config;
6 import cboxapp;
7 import window;
8 import types;
9 import gui.bar;
10 import kernel;
11 import monitor;
12 
13 import std.algorithm;
14 import std.c..string;
15 import x11.X;
16 import x11.Xlib;
17 import x11.keysymdef;
18 import x11.Xutil;
19 import x11.Xatom;
20 
21 /* color schemes */
22 enum 
23 { 
24     SchemeNorm, 
25     SchemeSel, 
26     SchemeLast 
27 }; 
28 
29 /// The colour scheme to use
30 struct ClrScheme 
31 {
32     Clr *fg;
33     Clr *bg;
34     Clr *border;
35 }
36 
37 class ThemeManager 
38 {   
39   
40   ClrScheme[SchemeLast] scheme;
41 
42   static ThemeManager instance() 
43   {
44     if (!instantiated_) {
45       synchronized {
46         if (instance_ is null) {
47           instance_ = new ThemeManager;
48         }
49         instantiated_ = true;
50       }
51     }
52     return instance_;
53   }
54 
55   ClrScheme getScheme(int type)
56   {
57      return this.scheme[type];
58   }
59 
60 
61  private:
62   this() 
63   {
64         /* init appearance */
65         scheme[SchemeNorm].border = new Clr(drw, normbordercolor);
66         scheme[SchemeNorm].bg = new Clr(drw, normbgcolor);
67         scheme[SchemeNorm].fg = new Clr(drw, normfgcolor);
68         scheme[SchemeSel].border = new Clr(drw, selbordercolor);
69         scheme[SchemeSel].bg = new Clr(drw, selbgcolor);
70         scheme[SchemeSel].fg = new Clr(drw, selfgcolor);  
71   }
72 
73   static bool instantiated_;  // Thread local
74   __gshared ThemeManager instance_;
75 
76  }
77 
78 /**
79  * Drw provides an interface for working with drawable surfaces.
80  */
81 struct Drw 
82 {
83     uint w, h; /// The width and height of the drawable area
84     Display *dpy; /// The X display
85     int screen; /// The X screen ID
86     Window root; /// The root window for this drawable
87     Drawable drawable; /// The X drawable encapsulated by this.
88     XGC gc; /// The X graphic context
89     ClrScheme *scheme; /// The colour scheme to use
90     Fnt *font; /// The X font to use for rendering text.
91 
92     /**
93      * Ctor to initialise the draw object
94      * Params:
95      *  dpy=        X display to render with.
96      *  screen=     X screen id
97      *  root=       Root X window for this drawable
98      *  w=          Width of the drawable
99      *  h=          Height of the drawable
100      * Example:
101      * ---
102      * drw = new Drw(AppDisplay.instance().dpy, screen, root, sw, sh);
103      * ---
104      */
105     this(Display* dpy, int screen, Window root, uint w, uint h) 
106     {
107         this.dpy = dpy;
108         this.screen = screen;
109         this.root = root;
110         this.w = w;
111         this.h = h;
112         this.drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
113         this.gc = XCreateGC(dpy, root, 0, null);
114         XSetLineAttributes(dpy, this.gc, 1, LineSolid, CapButt, JoinMiter);
115 
116     }
117 
118     /**
119      * Resize the drawable to a new width and height
120      * Params:
121      *  w=      Width
122      *  h=      Height
123      * Example:
124      * ---
125      * drw.resize(100, 100);
126      * ---
127      */
128     void resize(uint w, uint h)
129      {
130         this.w = w;
131         this.h = h;
132         if(this.drawable != 0) {
133             XFreePixmap(this.dpy, this.drawable);
134         }
135         this.drawable = XCreatePixmap(this.dpy, this.root, w, h, DefaultDepth(this.dpy, this.screen));
136     }
137 
138     /**
139      * Set the font to use for rendering.
140      * Params:
141      *  font=       Pointer to the font to use.
142      */
143     void setfont(Fnt *font) 
144     {
145         this.font = font;
146     }
147 
148     /**
149      * Set the scheme for this drawable
150      * Params:
151      *  scheme = Pointer to the scheme to use
152      */
153     void setscheme(ClrScheme *scheme)
154     {
155         if(scheme)
156             this.scheme = scheme;
157     }
158 
159     /**
160      * Draw a rectangle to the X display using the current settings. Note that
161      * filled and empty are not mutually exclusive.
162      * Params:
163      *  x=      Left edge of the rect
164      *  y=      Top edge of the rect
165      *  w=      Width of the rect
166      *  h=      Height of the rect
167      *  filled= If true the rect will be filled
168      *  empty=  If true the rect will be empty
169      *  invert= If true the colours will be inverted.
170      * Example:
171      * ---
172      * drw.rect(10, 10, 90, 90, true, false, false);
173      * ---
174      */
175     void rect(int x, int y, uint w, uint h, int filled, int empty, int invert) 
176     {
177         int dx;
178 
179         if(!this.font || !this.scheme)
180             return;
181         XSetForeground(this.dpy, this.gc, invert ? this.scheme.bg.rgb : this.scheme.fg.rgb);
182         dx = (this.font.ascent + this.font.descent + 2) / 4;
183         if(filled)
184             XFillRectangle(this.dpy, this.drawable, this.gc, x+1, y+1, dx+1, dx+1);
185         else if(empty)
186             XDrawRectangle(this.dpy, this.drawable, this.gc, x+1, y+1, dx, dx);
187     }
188 
189     /**
190      * Render some text to the display using the current font.
191      * Params:
192      *  x=      Left edge of the text area
193      *  y=      Top of the text area
194      *  w=      Width of the text area
195      *  h=      Height of the text area
196      *  text=   Text to write
197      *  invert= true the text bg/fg coluors will be inverted
198      * Example:
199      * ---
200      * drw.text(10, 10, 100, 100, "this is a test", false);
201      * ---
202      */
203     void text(int x, int y, uint w, uint h, in string text, int invert) 
204     {
205         char[256] buf;
206         Extnts tex;
207 
208         if(!this.scheme) {
209             return;
210         }
211         XSetForeground(this.dpy, this.gc, invert ? this.scheme.fg.rgb : this.scheme.bg.rgb);
212         XFillRectangle(this.dpy, this.drawable, this.gc, x, y, w, h);
213         if(!text || !this.font) {
214             return;
215         }
216         this.font.getexts(text, &tex);
217         auto th = this.font.ascent + this.font.descent;
218         auto ty = y + (h / 2) - (th / 2) + this.font.ascent;
219         auto tx = x + (h / 2);
220         /* shorten text if necessary */
221         auto len = min(text.length, buf.sizeof);        
222         for(; len && (tex.w > w - tex.h || w < tex.h); len--) {
223             this.font.getexts(text[0..len], &tex);
224         }
225         if(!len) {
226             return;
227         }
228         memcpy(buf.ptr, text.ptr, len);
229 
230         XSetForeground(this.dpy, this.gc, invert ? this.scheme.bg.rgb : this.scheme.fg.rgb);
231         if(this.font.set)
232             XmbDrawString(this.dpy, this.drawable, this.font.set, this.gc, tx, ty, buf.ptr, cast(uint)(len));
233         else
234             XDrawString(this.dpy, this.drawable, this.gc, tx, ty, buf.ptr, cast(int)len);
235     }
236 
237     /**
238      * Copy the drawable area to a window.
239      * Params:
240      *  win= Destination to copy to.
241      *  x=      Left edge of area to copy
242      *  y=      Top of area to copy
243      *  w=      Width of area to copy
244      *  h=      Height of area to copy
245      * Example:
246      * ---
247      * drw.map(win, 10, 10, 100, 100);
248      * ---
249      */
250     void map(Window win, int x, int y, uint w, uint h) 
251     {
252         XCopyArea(this.dpy, this.drawable, win, this.gc, x, y, w, h, x, y);
253         XSync(this.dpy, false);
254     }
255 
256     /**
257      * Release the GC memory used for the Drw object
258      * Params:
259      *  drw = Drw object to release
260      */
261     static void free(Drw* drw) 
262     {
263         drw.destroy;
264         DGC.free(drw);
265     }
266 
267     /**
268      * Destroy the X resources used by this drawable.
269      */
270     void destroy() 
271     {
272         XFreePixmap(this.dpy, this.drawable);
273         XFreeGC(this.dpy, this.gc);
274     }
275 
276 }