Subversion Repositories Filer-Free

Rev

Rev 29 | Rev 31 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
21 gdshaw@RISCPKG.ORG 1
// This file is part of the free Filer module for RISC OS.
2
// Copyright  2007 Graham Shaw.
3
// Redistribution and modification are permitted under the terms of the
4
// GNU General Public License (version 2 or any later version).
5
 
6
#include <cstring>
7
 
8
#include "template_loader.h"
25 gdshaw@RISCPKG.ORG 9
#include "layout_method.h"
21 gdshaw@RISCPKG.ORG 10
#include "filer_window.h"
11
#include "filer_application.h"
12
 
13
filer_window::filer_window(filer_application* app,const char* pathname,
25 gdshaw@RISCPKG.ORG 14
        const os_box& box,const filer_options& options):
21 gdshaw@RISCPKG.ORG 15
        window(app),
16
        _pathname(new char[std::strlen(pathname)+1]),
25 gdshaw@RISCPKG.ORG 17
        _options(options),
18
        _directory(options.sort()),
19
        _xcsize(68),
20
        _ycsize(68),
21
        _xccount(1),
22
        _yccount(1)
21 gdshaw@RISCPKG.ORG 23
{
24
        // Copy pathname into buffer owned by this object.
25
        std::strcpy(_pathname,pathname);
26
 
27
        // Load directory listing.
28
        reload();
29
 
30
        // Create window from template.
31
        template_loader loader("directory","Resources:$.Resources.Filer.Templates");
32
        wimp_window& wblock=loader;
33
        wblock.title_flags|=wimp_ICON_INDIRECTED;
34
        wblock.title_data.indirected_text.text=_pathname;
35
        wblock.title_data.indirected_text.validation="";
36
        wblock.title_data.indirected_text.size=strlen(_pathname);
37
        wblock.visible=box;
38
        wblock.extent.x0=0;
39
        wblock.extent.y0=-(box.y1-box.y0);
40
        wblock.extent.x1=box.x1-box.x0;
41
        wblock.extent.y1=0;
28 gdshaw@RISCPKG.ORG 42
        wblock.flags|=wimp_WINDOW_IGNORE_XEXTENT;
21 gdshaw@RISCPKG.ORG 43
        wblock.icon_count=0;
44
        create_window(wblock);
45
 
46
        // Resize extent to match actual visible area.
47
        wimp_window_state wstate;
48
        get_window_state(wstate);
49
        os_box extent;
50
        extent.x0=0;
51
        extent.y0=-(wstate.visible.y1-wstate.visible.y0);
52
        extent.x1=wstate.visible.x1-wstate.visible.x0;
53
        extent.y1=0;
54
        window::set_extent(extent);
55
 
25 gdshaw@RISCPKG.ORG 56
        // Open window, but keep it hidden from view.
21 gdshaw@RISCPKG.ORG 57
        wimp_window_info winfo;
58
        get_window_info_header(winfo);
59
        wimp_open open;
60
        open.visible.x0=winfo.visible.x0;
61
        open.visible.y0=winfo.visible.y1-(winfo.extent.y1-winfo.extent.y0);
62
        open.visible.x1=winfo.visible.x0+(winfo.extent.x1-winfo.extent.x0);
63
        open.visible.y1=winfo.visible.y1;
64
        open.visible=winfo.visible;
65
        open.xscroll=0;
66
        open.yscroll=0;
25 gdshaw@RISCPKG.ORG 67
        open.next=wimp_HIDDEN;
68
        open_window(open);
69
 
70
        // Reformat content of window.
71
        reformat();
72
 
73
        // Reopen window, now making it visible.
74
        get_window_state(wstate);
75
        open.visible=wstate.visible;
76
        open.xscroll=wstate.xscroll;
77
        open.yscroll=wstate.yscroll;
21 gdshaw@RISCPKG.ORG 78
        open.next=wimp_TOP;
79
        open_window(open);
80
}
81
 
82
filer_window::~filer_window()
83
{
84
        // Delete pathname buffer.
85
        delete[] _pathname;
86
}
87
 
88
void filer_window::handle_redraw_request(wimp_draw& block)
89
{
25 gdshaw@RISCPKG.ORG 90
        // Fetch layout.
91
        layout_method& layout=_options.layout();
92
        int xgap=layout.xgap();
93
        int ygap=layout.ygap();
94
 
21 gdshaw@RISCPKG.ORG 95
        int more=0;
96
        xwimp_redraw_window(&block,&more);
97
        while (more)
98
        {
25 gdshaw@RISCPKG.ORG 99
                // Get clipping coordinates with respect to this window.
100
                int xmin=block.clip.x0-block.box.x0+block.xscroll-xgap;
101
                int ymin=block.clip.y0-block.box.y1+block.yscroll+ygap;
102
                int xmax=block.clip.x1-block.box.x0+block.xscroll-xgap;
103
                int ymax=block.clip.y1-block.box.y1+block.yscroll+ygap;
104
 
105
                // Determine which cells are within clipping box.
106
                int xcmin=(xmin)/(_xcsize+xgap);
107
                int ycmin=(-ymax)/(_ycsize+ygap);
108
                int xcmax=(xmax-1)/(_xcsize+xgap)+1;
109
                int ycmax=(-ymin-1)/(_ycsize+ygap)+1;
110
                if (xcmin<0) xcmin=0;
111
                if (ycmin<0) ycmin=0;
112
                if (xcmax>_xccount) xcmax=_xccount;
113
                if (ycmax>_yccount) ycmax=_yccount;
114
 
115
                // Iterate over cells to be redrawn.
116
                for (int yc=ycmin;yc<ycmax;++yc)
117
                {
118
                        for (int xc=xcmin;xc<xcmax;++xc)
119
                        {
120
                                // Determine whether cell is occupied.
30 gdshaw@RISCPKG.ORG 121
                                unsigned int i=xc+yc*_xccount;
122
                                if (i<_directory.size())
25 gdshaw@RISCPKG.ORG 123
                                {
124
                                        // Redraw cell.
125
                                        os_box box;
126
                                        box.x0=xc*(_xcsize+xgap)+xgap;
127
                                        box.y0=-yc*(_ycsize+ygap)-_ycsize-ygap;
128
                                        box.x1=box.x0+_xcsize;
129
                                        box.y1=box.y0+_ycsize;
130
                                        layout.plot(box,*_directory[i],
131
                                                _directory[i].selected(),_options);
132
                                }
133
                        }
134
                }
135
 
21 gdshaw@RISCPKG.ORG 136
                xwimp_get_rectangle(&block,&more);
137
        }
138
}
139
 
28 gdshaw@RISCPKG.ORG 140
void filer_window::handle_open_request(wimp_open& block)
141
{
142
        int xccount=_xccount;
143
        int yccount=_yccount;
144
        reformat(block.visible.x1-block.visible.x0);
145
        xwimp_open_window(&block);
146
        if (_xccount!=xccount||_yccount!=yccount) force_redraw();
147
}
148
 
29 gdshaw@RISCPKG.ORG 149
void filer_window::handle_close_request(wimp_close& block)
150
{
151
        wimp_pointer pointer;
152
        xwimp_get_pointer_info(&pointer);
153
 
154
        if (pointer.buttons&wimp_CLICK_ADJUST)
155
        {
156
                os_coord offset;
157
                offset.x=0;
158
                offset.y=0;
159
                open_parent(offset);
160
        }
161
 
162
        delete this;
163
}
164
 
30 gdshaw@RISCPKG.ORG 165
void filer_window::handle_mouse_click(wimp_pointer& block)
166
{
167
        // Fetch layout.
168
        layout_method& layout=options().layout();
169
 
170
        // Find cell under pointer.
171
        unsigned int index=find_cell(block.pos);
172
 
173
        if (block.buttons&(wimp_SINGLE_SELECT|wimp_SINGLE_ADJUST))
174
        {
175
                // If single select click then first de-select everything.
176
                if (block.buttons&wimp_SINGLE_SELECT) select_all(0);
177
 
178
                // If click within a cell then select that cell.
179
                if (index!=directory::npos)
180
                {
181
                        _directory[index].selected(!_directory[index].selected());
182
                        force_redraw_cell(index);
183
                }
184
        }
185
}
186
 
21 gdshaw@RISCPKG.ORG 187
void filer_window::reload()
188
{
189
        static int buffer[256];
190
        _directory.load(_pathname,buffer,sizeof(buffer));
191
}
25 gdshaw@RISCPKG.ORG 192
 
193
void filer_window::reformat()
194
{
195
        wimp_window_state wstate;
196
        get_window_state(wstate);
197
        reformat(wstate.visible.x1-wstate.visible.x0);
198
}
199
 
200
void filer_window::reformat(int xsize)
201
{
202
        // Fetch layout.
203
        layout_method& layout=options().layout();
204
        int xgap=layout.xgap();
205
        int ygap=layout.ygap();
206
 
207
        // Calculate cell size.  This must be able to accommodate
208
        // - the minimum cell size for the chosen layout, and
209
        // - the actual size occupied by each file to be listed.
210
        os_coord csize=layout.min_size(_options);
211
        for (unsigned int i=0;i!=_directory.size();++i)
212
        {
213
                os_coord size=layout.size(*_directory[i],_options);
214
                if (size.x>csize.x) csize.x=size.x;
215
                if (size.y>csize.y) csize.y=size.y;
216
        }
217
 
218
        // Apply the calculated cell size.
219
        _xcsize=csize.x;
220
        _ycsize=csize.y;
221
 
222
        // Determine number of rows and columns.
223
        _xccount=xsize/(_xcsize+xgap);
224
        if (_xccount<1) _xccount=1;
225
        _yccount=(_directory.size()+_xccount-1)/_xccount;
226
        if (_yccount<1) _yccount=1;
227
 
228
        // Calculate new extent.
229
        int extent_xsize=_xccount*(_xcsize+xgap)+xgap;
230
        int extent_ysize=_yccount*(_ycsize+ygap)+ygap;
231
 
28 gdshaw@RISCPKG.ORG 232
        // Do not force the window to become narrower than the width requested,
25 gdshaw@RISCPKG.ORG 233
        // unless there are too few directory entries to justify that width.
234
        if (extent_xsize<xsize)
235
        {
236
                extent_xsize=xsize;
237
                if (((extent_xsize+_xcsize-1)/(_xcsize+xgap))>
238
                        static_cast<int>(_directory.size()))
239
                {
240
                        extent_xsize=_directory.size()*(_xcsize+xgap)+xgap;
241
                }
242
        }
243
 
244
        // Apply the calculated extent.
245
        os_box extent;
246
        extent.x0=0;
247
        extent.y0=-extent_ysize;
248
        extent.x1=extent_xsize;
249
        extent.y1=0;
250
        set_extent(extent);
251
}
29 gdshaw@RISCPKG.ORG 252
 
30 gdshaw@RISCPKG.ORG 253
unsigned int filer_window::find_cell(const os_coord& p)
254
{
255
        layout_method& layout=options().layout();
256
        int xgap=layout.xgap();
257
        int ygap=layout.ygap();
258
 
259
        wimp_window_state state;
260
        get_window_state(state);
261
        int x=p.x-state.visible.x0+state.xscroll-xgap;
262
        int y=p.y-state.visible.y1+state.yscroll+ygap;
263
 
264
        int xc=x/(_xcsize+xgap);
265
        int yc=(-y)/(_ycsize+ygap);
266
        unsigned int index=xc+yc*_xccount;
267
 
268
        x-=xc*(_xcsize+xgap);
269
        y+=yc*(_ycsize+ygap);
270
 
271
        int found=(x>=0)&&(y>=-_ycsize)&&(x<_xcsize)&&(y<0)&&
272
                (xc>=0)&&(yc>=0)&&(xc<_xccount)&&(yc<_yccount)&&
273
                (index<_directory.size());
274
 
275
        return (found)?index:directory::npos;
276
}
277
 
278
void filer_window::force_redraw_cell(unsigned int index)
279
{
280
        layout_method& layout=options().layout();
281
        int xgap=layout.xgap();
282
        int ygap=layout.ygap();
283
 
284
        int xc=index%_xccount;
285
        int yc=index/_xccount;
286
 
287
        os_box box;
288
        box.x0=xgap+xc*(_xcsize+xgap);
289
        box.y0=-(yc+1)*(_ycsize+ygap);
290
        box.x1=box.x0+_xcsize;
291
        box.y1=box.y0+_ycsize;
292
        force_redraw(box);
293
}
294
 
295
void filer_window::select_all(int selected)
296
{
297
        layout_method& layout=options().layout();
298
        int xgap=layout.xgap();
299
        int ygap=layout.ygap();
300
 
301
        int xc_min=_xccount;
302
        int yc_min=_yccount;
303
        int xc_max=0;
304
        int yc_max=0;
305
 
306
        for (unsigned int i=0;i!=_directory.size();++i)
307
        {
308
                if (_directory[i].selected()!=selected)
309
                {
310
                        _directory[i].selected(selected);
311
 
312
                        int xc=i%_xccount;
313
                        int yc=i/_xccount;
314
                        if (xc<xc_min) xc_min=xc;
315
                        if (yc<yc_min) yc_min=yc;
316
                        if (xc+1>xc_max) xc_max=xc+1;
317
                        if (yc+1>yc_max) yc_max=yc+1;
318
                }
319
        }
320
 
321
        if ((xc_max>xc_min)&&(yc_max>yc_min))
322
        {
323
                os_box box;
324
                box.x0=xgap+xc_min*(_xcsize+xgap);
325
                box.y0=-yc_max*(_ycsize+ygap);
326
                box.x1=xc_max*(_xcsize+xgap);
327
                box.y1=-ygap-yc_min*(_ycsize+ygap);
328
                force_redraw(box);
329
        }
330
}
331
 
29 gdshaw@RISCPKG.ORG 332
void filer_window::open_parent(const os_coord& offset) const
333
{
334
        // Determine whether there is a parent directory.
335
        char* lastdot=strrchr(_pathname,'.');
336
        if (lastdot&&strcmp(lastdot+1,"$"))
337
        {
338
                // Find top-left corner of this window.
339
                wimp_window_state state;
340
                get_window_state(state);
341
 
342
                // Add offset to give top-left corner of new window.
343
                os_box box;
344
                box.x0=state.visible.x0+offset.x;
345
                box.y1=state.visible.y1+offset.y;
346
                box.x1=box.x0;
347
                box.y0=box.y1;
348
 
349
                // Open new window.
350
                *lastdot=0;
351
                new filer_window((filer_application*)parent_application(),
352
                        _pathname,box,_options);
353
                *lastdot='.';
354
        }
355
}