]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/mru.cpp
reformat code! now the code is only ugly on the *inside*
[xonotic/netradiant.git] / radiant / mru.cpp
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "mru.h"
23
24 #include <string.h>
25 #include <stdio.h>
26 #include <gtk/gtk.h>
27
28 #include "os/file.h"
29 #include "generic/callback.h"
30 #include "stream/stringstream.h"
31 #include "convert.h"
32
33 #include "gtkutil/menu.h"
34 #include "map.h"
35 #include "qe3.h"
36
37 const int MRU_MAX = 4;
38 namespace {
39     GtkMenuItem *MRU_items[MRU_MAX];
40     std::size_t MRU_used;
41     typedef CopiedString MRU_filename_t;
42     MRU_filename_t MRU_filenames[MRU_MAX];
43     typedef const char *MRU_key_t;
44     MRU_key_t MRU_keys[MRU_MAX] = {"File0", "File1", "File2", "File3"};
45 }
46
47 inline const char *MRU_GetText(std::size_t index)
48 {
49     return MRU_filenames[index].c_str();
50 }
51
52 class EscapedMnemonic {
53     StringBuffer m_buffer;
54 public:
55     EscapedMnemonic(std::size_t capacity) : m_buffer(capacity)
56     {
57         m_buffer.push_back('_');
58     }
59
60     const char *c_str() const
61     {
62         return m_buffer.c_str();
63     }
64
65     void push_back(char c)
66     { // not escaped
67         m_buffer.push_back(c);
68     }
69
70     std::size_t write(const char *buffer, std::size_t length)
71     {
72         for (const char *end = buffer + length; buffer != end; ++buffer) {
73             if (*buffer == '_') {
74                 m_buffer.push_back('_');
75             }
76
77             m_buffer.push_back(*buffer);
78         }
79         return length;
80     }
81 };
82
83 template<typename T>
84 inline EscapedMnemonic &operator<<(EscapedMnemonic &ostream, const T &t)
85 {
86     return ostream_write(ostream, t);
87 }
88
89
90 void MRU_updateWidget(std::size_t index, const char *filename)
91 {
92     EscapedMnemonic mnemonic(64);
93     mnemonic << Unsigned(index + 1) << "- " << filename;
94     gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_bin_get_child(GTK_BIN(MRU_items[index]))), mnemonic.c_str());
95 }
96
97 void MRU_SetText(std::size_t index, const char *filename)
98 {
99     MRU_filenames[index] = filename;
100     MRU_updateWidget(index, filename);
101 }
102
103 void MRU_AddFile(const char *str)
104 {
105     std::size_t i;
106     const char *text;
107
108     // check if file is already in our list
109     for (i = 0; i < MRU_used; i++) {
110         text = MRU_GetText(i);
111
112         if (strcmp(text, str) == 0) {
113             // reorder menu
114             for (; i > 0; i--) {
115                 MRU_SetText(i, MRU_GetText(i - 1));
116             }
117
118             MRU_SetText(0, str);
119
120             return;
121         }
122     }
123
124     if (MRU_used < MRU_MAX) {
125         MRU_used++;
126     }
127
128     // move items down
129     for (i = MRU_used - 1; i > 0; i--) {
130         MRU_SetText(i, MRU_GetText(i - 1));
131     }
132
133     MRU_SetText(0, str);
134     gtk_widget_set_sensitive(ui::MenuItem::from(MRU_items[0]), TRUE);
135     ui::MenuItem::from(MRU_items[MRU_used - 1]).show();
136 }
137
138 void MRU_Init()
139 {
140     if (MRU_used > MRU_MAX) {
141         MRU_used = MRU_MAX;
142     }
143 }
144
145 void MRU_AddWidget(ui::MenuItem widget, std::size_t pos)
146 {
147     if (pos < MRU_MAX) {
148         MRU_items[pos] = widget;
149         if (pos < MRU_used) {
150             MRU_updateWidget(pos, MRU_GetText(pos));
151             gtk_widget_set_sensitive(ui::MenuItem::from(MRU_items[0]), TRUE);
152             ui::MenuItem::from(MRU_items[pos]).show();
153         }
154     }
155 }
156
157 void MRU_Activate(std::size_t index)
158 {
159     char text[1024];
160     strcpy(text, MRU_GetText(index));
161
162     if (file_readable(text)) { //\todo Test 'map load succeeds' instead of 'file is readable'.
163         MRU_AddFile(text);
164         Map_RegionOff();
165         Map_Free();
166         Map_LoadFile(text);
167     } else {
168         MRU_used--;
169
170         for (std::size_t i = index; i < MRU_used; i++) {
171             MRU_SetText(i, MRU_GetText(i + 1));
172         }
173
174         if (MRU_used == 0) {
175             auto label = ui::Label::from(gtk_bin_get_child(GTK_BIN(MRU_items[0])));
176             label.text("Recent Files");
177             gtk_widget_set_sensitive(ui::MenuItem::from(MRU_items[0]), FALSE);
178         } else {
179             ui::MenuItem::from(MRU_items[MRU_used]).hide();
180         }
181     }
182 }
183
184
185 class LoadMRU {
186     std::size_t m_number;
187 public:
188     LoadMRU(std::size_t number)
189             : m_number(number)
190     {
191     }
192
193     void load()
194     {
195         if (ConfirmModified("Open Map")) {
196             MRU_Activate(m_number - 1);
197         }
198     }
199 };
200
201 typedef MemberCaller<LoadMRU, void(), &LoadMRU::load> LoadMRUCaller;
202
203 LoadMRU g_load_mru1(1);
204 LoadMRU g_load_mru2(2);
205 LoadMRU g_load_mru3(3);
206 LoadMRU g_load_mru4(4);
207
208 void MRU_constructMenu(ui::Menu menu)
209 {
210     {
211         auto item = create_menu_item_with_mnemonic(menu, "_1", LoadMRUCaller(g_load_mru1));
212         gtk_widget_set_sensitive(item, FALSE);
213         MRU_AddWidget(item, 0);
214     }
215     {
216         auto item = create_menu_item_with_mnemonic(menu, "_2", LoadMRUCaller(g_load_mru2));
217         item.hide();
218         MRU_AddWidget(item, 1);
219     }
220     {
221         auto item = create_menu_item_with_mnemonic(menu, "_3", LoadMRUCaller(g_load_mru3));
222         item.hide();
223         MRU_AddWidget(item, 2);
224     }
225     {
226         auto item = create_menu_item_with_mnemonic(menu, "_4", LoadMRUCaller(g_load_mru4));
227         item.hide();
228         MRU_AddWidget(item, 3);
229     }
230 }
231
232 #include "preferencesystem.h"
233 #include "stringio.h"
234
235 void MRU_Construct()
236 {
237     GlobalPreferenceSystem().registerPreference("Count", make_property_string(MRU_used));
238
239     for (std::size_t i = 0; i != MRU_MAX; ++i) {
240         GlobalPreferenceSystem().registerPreference(MRU_keys[i], make_property_string(MRU_filenames[i]));
241     }
242
243     MRU_Init();
244 }
245
246 void MRU_Destroy()
247 {
248 }