3 Copyright (C) 2022 Cockos Inc
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
27 #include "../../swell/swell.h"
29 #include "../../win32_utf8.h"
30 #include "../../wingui/wndsize.h"
31 #include "../../filebrowse.h"
32 #include "../../wdlstring.h"
34 #include "../../assocarray.h"
36 #include "../../localize/localize.h"
37 #include "../../lineparse.h"
39 #define WDL_HASSTRINGS_REWUTF8_HOOK(str, base) \
40 if ((str) > (base)) switch ((str)[0]) { \
41 case 'r': case 'n': case 't': case '0': if ((str)[-1] == '\\') (str)--; break; \
42 case 'd': case 's': case 'f': case 'g': case 'c': case 'u': if ((str)[-1] == '%') (str)--; break; \
44 #include "../../has_strings.h"
50 #define HDF_SORTUP 0x0400
53 #define HDF_SORTDOWN 0x0200
56 void ListView_SetHeaderSortArrow(HWND hlist
, int col
, int dir
)
58 HWND hhdr
=ListView_GetHeader(hlist
);
60 for (int i
=0; i
< Header_GetItemCount(hhdr
); ++i
)
62 HDITEM hi
= { HDI_FORMAT
, 0, };
63 Header_GetItem(hhdr
, i
, &hi
);
64 hi
.fmt
&= ~(HDF_SORTUP
|HDF_SORTDOWN
);
65 if (i
== col
) hi
.fmt
|= (dir
> 0 ? HDF_SORTUP
: HDF_SORTDOWN
);
66 Header_SetItem(hhdr
, i
, &hi
);
71 template<class A
, class B
> static void Restore_ListSelState(HWND hlist
, const WDL_TypedBuf
<A
> *order
, const B
*st
)
74 SendMessage(hlist
,WM_SETREDRAW
,FALSE
,0);
77 const int n
= order
->GetSize();
79 for (x
= 0; x
< n
; x
++)
81 bool sel
= st
->Get(order
->Get()[x
]);
82 if (frow
< 0 && sel
) frow
= x
;
83 ListView_SetItemState(hlist
, x
, sel
? LVIS_SELECTED
: 0, LVIS_SELECTED
);
86 ListView_EnsureVisible(hlist
, frow
, FALSE
);
88 SendMessage(hlist
,WM_SETREDRAW
,TRUE
,0);
92 template<class A
, class B
> static void Save_ListSelState(HWND hlist
, const WDL_TypedBuf
<A
> *order
, B
*st
)
95 const int n
= order
->GetSize();
96 for (x
= 0; x
< n
; x
++)
98 if (ListView_GetItemState(hlist
,x
,LVIS_SELECTED
)) st
->AddUnsorted(order
->Get()[x
], true);
105 #if !defined(_WIN32) && !defined(__APPLE__)
109 HINSTANCE g_hInstance
;
110 WDL_FastString g_ini_file
;
113 COL_STATE
=0, // if we edit these need to edit the IDs of ID_COL_* in resource.h
118 COL_COMMON_LOCALIZED
,
124 char *template_str
, *pack_str
;
126 char *key_desc
; // key name + comments
130 static void freeptrs(pack_rec r
)
133 free(r
.template_str
);
138 struct editor_instance
{
139 editor_instance() : m_recs(true, pack_rec::freeptrs
),
140 m_column_no_searchflags(0), m_sort_col(COL_ID
), m_sort_rev(false),
141 m_hwnd(NULL
), m_dirty(false) { }
142 ~editor_instance() { }
144 WDL_FastString m_pack_fn
;
146 WDL_StringKeyedArray2
<pack_rec
> m_recs
;
147 WDL_TypedBuf
<int> m_display_order
;
148 int m_column_no_searchflags
; // bits for exclude from search per column
155 WDL_WndSizer m_resize
;
157 void load_file(const char *filename
, bool is_template
);
158 void save_file(const char *filename
);
162 void sort_display_order();
163 void on_sort_change();
165 const char *get_rec_value(const pack_rec
*r
, const char *k
, int w
) const
167 __LOCALIZE_LCACHE("(empty)","langpackedit",empt
);
172 if (!r
->template_str
)
174 if (strstr(k
,":5CA1E00000000000")) return "";
175 __LOCALIZE_LCACHE("not-in-template","langpackedit",nit
);
178 if (r
->pack_str
) return "";
179 if (r
->common_idx
>=0)
182 pack_rec
*r2
= m_recs
.EnumeratePtr(r
->common_idx
,&k2
);
183 if (WDL_NORMALLY(r2
&& k2
))
185 WDL_ASSERT(!strcmp(strstr(k2
,":"),strstr(k
,":")));
186 __LOCALIZE_LCACHE("localized-in-common","langpackedit",lic
);
187 __LOCALIZE_LCACHE("common-not-localized","langpackedit",cnl
);
188 if (r2
->pack_str
) return lic
;
192 return "not-localized";
194 case COL_ID
: return r
->key_desc
? r
->key_desc
: k
;
195 case COL_TEMPLATE
: return r
->template_str
;
196 case COL_LOCALIZED
: return r
->pack_str
== NULL
? "" : r
->pack_str
[0] ? r
->pack_str
: empt
;
197 case COL_COMMON_LOCALIZED
:
198 if (r
->common_idx
>=0)
201 pack_rec
*r2
= m_recs
.EnumeratePtr(r
->common_idx
,&k2
);
202 if (WDL_NORMALLY(r2
&& k2
))
204 WDL_ASSERT(!strcmp(strstr(k2
,":"),strstr(k
,":")));
205 return r2
->pack_str
== NULL
? "" : r2
->pack_str
[0] ? r2
->pack_str
: empt
;
214 const char *get_row_value(int row
, int w
) const
216 if (row
< 0 || row
>= m_display_order
.GetSize()) return "<err>";
218 pack_rec
*r
= m_recs
.EnumeratePtr(m_display_order
.Get()[row
],&k
);
219 if (!r
|| !k
) return "<ERR>";
220 const char *rv
= get_rec_value(r
,k
,w
);
224 bool edit_row(int rec_idx
, int other_action
=IDC_LOCALIZED_STRING
);
225 bool on_key(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
);
226 void item_context_menu();
241 snprintf(tmp
,sizeof(tmp
),"%s%sLangPackEdit%s",
242 m_pack_fn
.get_filepart(),m_pack_fn
.GetLength() ? " - ": "",m_dirty
? __LOCALIZE(" (unsaved)","langpackedit") :"");
243 SetWindowText(m_hwnd
,tmp
);
250 int a
= MessageBox(m_hwnd
,__LOCALIZE("LangPack is not saved, save before exiting?","langpackedit"),
251 __LOCALIZE("Unsaved","langpackedit"),MB_YESNOCANCEL
);
252 if (a
== IDCANCEL
) return false;
253 if (a
== IDNO
) m_dirty
= false;
254 else SendMessage(m_hwnd
,WM_COMMAND
,IDC_PACK_SAVE
,0);
260 static void del_array(WDL_KeyedArray
<WDL_UINT64
, char *> *d
) { delete d
; }
262 static void format_section_id(char *buf
, size_t bufsz
, const char *section
, WDL_UINT64 id
)
264 snprintf(buf
,bufsz
,"%s:%08X%08X",section
, (int)(id
>>32),(int)(id
&0xffffffff));
267 static const char *parse_section_id(const char *k
, char *buf
, int bufsz
) // returns ID or NULL
269 if (buf
) lstrcpyn_safe(buf
, k
, bufsz
);
271 char *base
= buf
? buf
: (char*)k
, *p
= base
;
273 while (p
> base
&& *p
!= ':') p
--;
274 if (WDL_NOT_NORMALLY(p
==base
)) return NULL
;
279 void editor_instance::save_file(const char *filename
)
281 FILE *fp
= fopen(filename
,"wb");
284 MessageBox(m_hwnd
,__LOCALIZE("Error opening file for writing","langpackedit"),
285 __LOCALIZE("Error","langpackedit"),MB_OK
);
290 if (WDL_NORMALLY(m_hwnd
))
291 GetDlgItemText(m_hwnd
,IDC_COMMENTS
,buf
,sizeof(buf
));
292 WDL_remove_trailing_whitespace(buf
);
293 fprintf(fp
,"%s\r\n",buf
);
298 for (int x
= 0; x
< m_recs
.GetSize(); x
++)
301 const pack_rec
*rec
= m_recs
.EnumeratePtr(x
,&k
);
302 if (!rec
->pack_str
) continue;
305 const char *id
= parse_section_id(k
,sec
,sizeof(sec
));
306 if (WDL_NORMALLY(id
))
308 if (stricmp(last_sec
,sec
))
310 lstrcpyn_safe(last_sec
,sec
,sizeof(last_sec
));
311 const char *trail
= "";
314 trail
= strstr(rec
->key_desc
," ");
315 trail
= trail
? (trail
+1) : "";
317 fprintf(fp
,"\r\n[%s]%s\r\n",sec
,trail
);
319 fprintf(fp
,"%s=%s\r\n",id
,rec
->pack_str
);
325 void editor_instance::load_file(const char *filename
, bool is_template
)
327 for (int x
= 0; x
< m_recs
.GetSize(); x
++)
329 pack_rec
*r
= m_recs
.EnumeratePtr(x
);
332 free(r
->template_str
);
333 r
->template_str
= NULL
;
342 WDL_StringKeyedArray
<char *> extra(true, WDL_StringKeyedArray
<char>::freecharptr
);
345 WDL_StringKeyedArray
< WDL_KeyedArray
<WDL_UINT64
, char *> * > r(false,del_array
);
346 WDL_LoadLanguagePackInternal(filename
,&r
,NULL
, is_template
, true, &extra
);
348 for (int si
= 0; si
< r
.GetSize(); si
++)
350 const char *sec_name
;
351 WDL_KeyedArray
<WDL_UINT64
, char *> *sec
= r
.Enumerate(si
,&sec_name
);
352 for (int i
= 0; i
< sec
->GetSize(); i
++)
355 const char *value
= sec
->Enumerate(i
,&id
);
356 if (WDL_NOT_NORMALLY(!value
)) break;
358 char rec_buf
[256], key_desc
[256];
359 format_section_id(rec_buf
,sizeof(rec_buf
),sec_name
, id
);
362 const char *p
= extra
.Get(sec_name
);
364 snprintf(key_desc
,sizeof(key_desc
),"%.100s %s",rec_buf
,p
);
369 pack_rec
*rec
= m_recs
.GetPtr(rec_buf
);
372 pack_rec newr
= { 0 };
373 if (is_template
) newr
.template_str
= strdup(value
);
374 else newr
.pack_str
= strdup(value
);
376 if (key_desc
[0]) newr
.key_desc
= strdup(key_desc
);
377 m_recs
.Insert(rec_buf
,newr
);
381 if (is_template
|| key_desc
[0])
384 rec
->key_desc
= key_desc
[0] ? strdup(key_desc
) : NULL
;
388 free(rec
->template_str
);
389 rec
->template_str
= strdup(value
);
394 rec
->pack_str
= strdup(value
);
405 SetDlgItemText(m_hwnd
,is_template
? IDC_TEMPLATE
: IDC_PACK
, *filename
? filename
: __LOCALIZE("(none)","langpackedit"));
413 snprintf(tmp
,sizeof(tmp
),"_initial_comment_%d",x
);
414 const char *p
= extra
.Get(tmp
);
416 if (fs
.GetLength()) fs
.Append("\r\n");
420 WDL_remove_trailing_whitespace((char *)fs
.Get());
421 SetDlgItemText(m_hwnd
,IDC_COMMENTS
,fs
.Get());
426 void editor_instance::cull_recs()
428 for (int x
= 0; x
< m_recs
.GetSize(); x
++)
430 pack_rec
*r
= m_recs
.EnumeratePtr(x
);
431 if (!r
->template_str
&& !r
->pack_str
)
432 m_recs
.DeleteByIndex(x
--);
436 void editor_instance::refresh_list()
438 HWND list
= WDL_NORMALLY(m_hwnd
) ? GetDlgItem(m_hwnd
,IDC_LIST
) : NULL
;
439 WDL_IntKeyedArray
<bool> selState
;
441 Save_ListSelState(list
, &m_display_order
, &selState
);
443 m_display_order
.Resize(0,false);
449 GetDlgItemText(m_hwnd
,IDC_FILTER
,filter
,sizeof(filter
));
450 WDL_makeSearchFilter(filter
, &lp
);
452 const bool do_filt
= lp
.getnumtokens()>0;
453 for (int x
= 0; x
< m_recs
.GetSize(); x
++)
455 const char *k
= NULL
;
456 pack_rec
*r
= m_recs
.EnumeratePtr(x
,&k
);
457 if (WDL_NOT_NORMALLY(!r
)) break;
459 if (strnicmp(k
,"common:",7))
461 const char *sid
= parse_section_id(k
,NULL
,0);
462 if (WDL_NORMALLY(sid
))
465 snprintf(tmp
,sizeof(tmp
),"common:%s",sid
);
466 r
->common_idx
= m_recs
.GetIdx(tmp
);
472 const char *strs
[COL_MAX
];
476 for (int c
=0; c
< COL_MAX
; c
++)
478 if (m_column_no_searchflags
& (1<<c
)) continue;
479 const char *v
= get_rec_value(r
,k
,c
);
480 if (v
) strs
[nc
++] = v
;
484 if (!do_filt
|| WDL_hasStringsEx2(strs
,nc
,&lp
))
485 m_display_order
.Add(&x
,1);
488 sort_display_order();
492 ListView_SetItemCount(list
, m_display_order
.GetSize());
493 Restore_ListSelState(list
, &m_display_order
, &selState
);
494 ListView_RedrawItems(list
, 0, m_display_order
.GetSize());
498 static editor_instance
*sort_inst
;
499 static int sort_func(const void *a
, const void *b
)
501 const int idx_a
= *(const int *)a
, idx_b
= *(const int *)b
;
502 int ret
= idx_a
< idx_b
? -1 : idx_a
> idx_b
? 1 : 0;
504 const int col
= sort_inst
->m_sort_col
;
510 case COL_COMMON_LOCALIZED
:
514 const pack_rec
*ar
= sort_inst
->m_recs
.EnumeratePtr(idx_a
,&ak
);
515 const pack_rec
*br
= sort_inst
->m_recs
.EnumeratePtr(idx_b
,&bk
);
516 const char *av
= ar
? sort_inst
->get_rec_value(ar
,ak
,col
) : NULL
;
517 const char *bv
= br
? sort_inst
->get_rec_value(br
,bk
,col
) : NULL
;
520 if (av
) while (*av
== ' ') av
++;
521 if (bv
) while (*bv
== ' ') bv
++;
522 if (col
== COL_ID
) ret
= stricmp(av
?av
:"",bv
?bv
:"");
523 else ret
= WDL_strcmp_logical_ex(av
?av
:"",bv
?bv
:"",0,WDL_STRCMP_LOGICAL_EX_FLAG_UTF8CONVERT
);
528 return sort_inst
->m_sort_rev
? -ret
: ret
;
532 void editor_instance::on_sort_change()
535 snprintf(tmp
, sizeof(tmp
), "%d", m_sort_col
);
536 WritePrivateProfileString("LangPackEdit", "sortcol", tmp
, g_ini_file
.Get());
537 WritePrivateProfileString("LangPackEdit", "sortrev", m_sort_rev
? "1" : "0", g_ini_file
.Get());
540 HWND list
= GetDlgItem(m_hwnd
,IDC_LIST
);
543 WDL_IntKeyedArray
<bool> selState
;
544 Save_ListSelState(list
, &m_display_order
, &selState
);
546 sort_display_order();
548 ListView_SetHeaderSortArrow(list
, m_sort_col
, (m_sort_rev
? -1 : 1));
549 ListView_SetItemCount(list
, m_display_order
.GetSize());
550 Restore_ListSelState(list
, &m_display_order
, &selState
);
552 ListView_RedrawItems(list
, 0, m_display_order
.GetSize());
555 void editor_instance::sort_display_order()
557 if (m_display_order
.GetSize() > 1)
560 qsort(m_display_order
.Get(), m_display_order
.GetSize(), sizeof(m_display_order
.Get()[0]), sort_func
);
565 WDL_DLGRET
editorProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
570 SetWindowLongPtr(hwndDlg
,GWLP_USERDATA
,lParam
);
572 void **p
= (void **)lParam
;
573 editor_instance
*edit
= (editor_instance
*)p
[0];
574 int item
= (int) (INT_PTR
) p
[1];
576 pack_rec
*rec
= edit
->m_recs
.EnumeratePtr(item
,&k
);
577 if (WDL_NORMALLY(rec
))
580 snprintf(tmp
,sizeof(tmp
),__LOCALIZE_VERFMT("Localize: %s","langpackedit"),k
);
581 SetWindowText(hwndDlg
,tmp
);
583 if (rec
->template_str
)
584 SetDlgItemText(hwndDlg
,IDC_TEMPLATE_STRING
,rec
->template_str
);
586 const char *common_str
= NULL
;
587 if (rec
->common_idx
>=0)
590 pack_rec
*r2
= edit
->m_recs
.EnumeratePtr(rec
->common_idx
,&k2
);
591 if (WDL_NORMALLY(r2
&& k2
))
593 WDL_ASSERT(!strcmp(strstr(k2
,":"),strstr(k
,":")));
594 SetDlgItemText(hwndDlg
,IDC_COMMON_STRING
,r2
->pack_str
? r2
->pack_str
: __LOCALIZE("(not yet localized)","langpackedit"));
595 common_str
= r2
->pack_str
;
598 else if (!strnicmp(k
,"common:",7))
600 ShowWindow(GetDlgItem(hwndDlg
,IDC_COMMON_LABEL
),SW_HIDE
);
601 ShowWindow(GetDlgItem(hwndDlg
,IDC_COMMON_STRING
),SW_HIDE
);
604 SetDlgItemText(hwndDlg
,IDC_COMMON_STRING
,__LOCALIZE("(not in [common])","langpackedit"));
606 if (rec
->pack_str
|| rec
->template_str
)
607 SetDlgItemText(hwndDlg
,IDC_LOCALIZED_STRING
,rec
->pack_str
? rec
->pack_str
:
608 common_str
? common_str
: rec
->template_str
);
613 switch (LOWORD(wParam
))
615 case IDC_REMOVE_LOCALIZATION
:
616 case IDC_COPY_TEMPLATE
:
619 void **p
= (void **)GetWindowLongPtr(hwndDlg
,GWLP_USERDATA
);
620 editor_instance
*edit
= (editor_instance
*)p
[0];
621 int item
= (int) (INT_PTR
) p
[1];
623 pack_rec
*rec
= edit
->m_recs
.EnumeratePtr(item
,&k
);
624 if (WDL_NORMALLY(rec
))
626 if (LOWORD(wParam
) == IDOK
)
629 GetDlgItemText(hwndDlg
,IDC_LOCALIZED_STRING
,buf
,sizeof(buf
));
631 rec
->pack_str
= strdup(buf
);
636 rec
->pack_str
= LOWORD(wParam
) == IDC_COPY_TEMPLATE
&& rec
->template_str
?
637 strdup(rec
->template_str
) : NULL
;
641 EndDialog(hwndDlg
,1);
644 EndDialog(hwndDlg
,0);
652 bool editor_instance::edit_row(int row
, int other_action
)
654 if (row
< 0 || row
>= m_display_order
.GetSize()) return false;
655 int rec_idx
= m_display_order
.Get()[row
];
657 WDL_ASSERT(rec_idx
>=0 && rec_idx
< m_recs
.GetSize());
659 if (other_action
&& other_action
!= IDC_LOCALIZED_STRING
)
662 pack_rec
*r
= m_recs
.EnumeratePtr(rec_idx
,&k
);
665 switch (other_action
)
667 case IDC_COMMON_STRING
:
668 if (r
->common_idx
>=0 && r
->common_idx
< m_recs
.GetSize())
669 rec_idx
= r
->common_idx
;
671 case IDC_REMOVE_NONLOCALIZATION
:
674 if (!r
->template_str
) return false;
675 if (strcmp(r
->template_str
,r
->pack_str
)) return false;
678 case IDC_REMOVE_LOCALIZATION
:
679 case IDC_COPY_TEMPLATE
:
680 if (other_action
== IDC_COPY_TEMPLATE
&& r
->pack_str
) return false; // do not modify already-localized strings
683 r
->pack_str
= other_action
== IDC_COPY_TEMPLATE
&& r
->template_str
? strdup(r
->template_str
) : NULL
;
688 if (WDL_NORMALLY(parse_section_id(k
,sec
,sizeof(sec
))))
690 lstrcatn(sec
,":5CA1E00000000000",sizeof(sec
));
691 if (!m_recs
.GetPtr(sec
))
693 pack_rec newr
= { 0 };
694 m_recs
.Insert(sec
,newr
);
695 int idx
= m_recs
.GetIdx(sec
);
696 if (WDL_NORMALLY(idx
>=0))
698 // added a rec, adjust indices and stick us at the end
699 for (int x
= 0; x
< m_display_order
.GetSize(); x
++)
701 if (m_display_order
.Get()[x
] >= idx
)
702 m_display_order
.Get()[x
]++;
704 m_display_order
.Add(idx
);
716 void *p
[2] = { this, (void *)(INT_PTR
) rec_idx
};
717 if (DialogBoxParam(g_hInstance
, MAKEINTRESOURCE(IDD_RENAME
), m_hwnd
, editorProc
, (LPARAM
)p
))
727 bool editor_instance::on_key(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
729 if (!m_hwnd
|| (hwnd
!= m_hwnd
&& !IsChild(m_hwnd
,hwnd
)))
733 if (msg
== WM_KEYDOWN
&& (wParam
=='S' || wParam
== 'O' || wParam
== 'T'))
735 bool shift
= !!(GetAsyncKeyState(VK_SHIFT
)&0x8000);
736 bool ctrl
= !!(GetAsyncKeyState(VK_CONTROL
)&0x8000);
739 bool alt
= !!(GetAsyncKeyState(VK_MENU
)&0x8000);
741 if (wParam
== 'S' && ctrl
) cmd
= alt
? IDC_PACK_SAVE_AS
: IDC_PACK_SAVE
;
742 else if (wParam
== 'O') cmd
= IDC_PACK_LOAD
;
743 else if (wParam
== 'T') cmd
= IDC_TEMPLATE_LOAD
;
747 SendMessage(m_hwnd
,WM_COMMAND
,cmd
,0);
754 HWND hlist
= GetDlgItem(m_hwnd
,IDC_LIST
);
755 if (hwnd
== hlist
|| IsChild(hlist
,hwnd
))
757 if (msg
== WM_KEYDOWN
) switch (wParam
)
760 SendMessage(m_hwnd
,WM_COMMAND
,IDC_LOCALIZED_STRING
,0);
770 SendMessage(m_hwnd
,WM_COMMAND
,IDC_REMOVE_LOCALIZATION
,0);
777 void editor_instance::item_context_menu()
779 HMENU menu
= LoadMenu(g_hInstance
, MAKEINTRESOURCE(IDR_CONTEXTMENU
));
782 TrackPopupMenu(GetSubMenu(menu
,0),0,p
.x
,p
.y
,0,m_hwnd
,NULL
);
786 const char *COL_DESCS
[COL_MAX
] = {
787 // !WANT_LOCALIZE_STRINGS_BEGIN:langpackedit
794 // !WANT_LOCALIZE_STRINGS_END
797 int COL_SIZES
[COL_MAX
] = {
806 editor_instance g_editor
;
807 WDL_DLGRET
mainProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
815 g_editor
.m_hwnd
= hwndDlg
;
818 HICON icon
=LoadIcon(g_hInstance
,MAKEINTRESOURCE(IDI_ICON1
));
819 SetClassLongPtr(hwndDlg
,GCLP_HICON
,(LPARAM
)icon
);
823 g_editor
.m_resize
.init(hwndDlg
);
824 g_editor
.m_resize
.init_item(IDC_FILTER
,0,0,1,0);
825 g_editor
.m_resize
.init_item(IDC_TEMPLATE
,0,0,1,0);
826 g_editor
.m_resize
.init_item(IDC_PACK
,0,0,1,0);
827 g_editor
.m_resize
.init_item(IDC_COMMENTS
,0,0,1,0);
828 g_editor
.m_resize
.init_item(IDC_LIST
,0,0,1,1);
831 HWND hlist
= GetDlgItem(hwndDlg
, IDC_LIST
);
833 int s
=LVS_EX_FULLROWSELECT
|LVS_EX_GRIDLINES
|LVS_EX_HEADERDRAGDROP
;
835 s
|=LVS_EX_DOUBLEBUFFER
;
837 ListView_SetExtendedListViewStyleEx(hlist
, s
,s
);
840 WDL_UTF8_HookListView(hlist
);
841 SendMessage(hlist
,LVM_SETUNICODEFORMAT
,1,0);
843 int colorder
[COL_MAX
];
844 for (int x
= 0; x
< COL_MAX
; x
++)
847 sprintf(buf
, "colwid_%d", x
);
848 int colw
=GetPrivateProfileInt("LangPackEdit", buf
, COL_SIZES
[x
], g_ini_file
.Get());
849 sprintf(buf
, "colorder_%d", x
);
850 colorder
[x
]=GetPrivateProfileInt("LangPackEdit", buf
, x
, g_ini_file
.Get());
852 LVCOLUMN lvc
= { LVCF_TEXT
|LVCF_WIDTH
, 0, colw
, (char*)__localizeFunc(COL_DESCS
[x
],"langpackedit",LOCALIZE_FLAG_NOCACHE
) };
853 ListView_InsertColumn(hlist
, x
, &lvc
);
855 ListView_SetColumnOrderArray(hlist
, COL_MAX
, colorder
);
860 GetPrivateProfileString("LangPackEdit","template","",buf
,sizeof(buf
),g_ini_file
.Get());
861 g_editor
.load_file(buf
,true);
863 GetPrivateProfileString("LangPackEdit","lastpack","",buf
,sizeof(buf
),g_ini_file
.Get());
864 g_editor
.load_file(buf
,false);
866 g_editor
.m_column_no_searchflags
= GetPrivateProfileInt("LangPackEdit","nosearchcols",0,g_ini_file
.Get());
867 g_editor
.m_sort_col
= GetPrivateProfileInt("LangPackEdit","sortcol",COL_ID
,g_ini_file
.Get());
868 g_editor
.m_sort_rev
= GetPrivateProfileInt("LangPackEdit","sortrev",0,g_ini_file
.Get()) > 0;
869 ListView_SetHeaderSortArrow(GetDlgItem(hwndDlg
,IDC_LIST
), g_editor
.m_sort_col
, (g_editor
.m_sort_rev
? -1 : 1));
870 g_editor
.m_pack_fn
.Set(buf
);
871 g_editor
.set_caption();
877 HWND hlist
= GetDlgItem(hwndDlg
,IDC_LIST
);
878 int colorder
[COL_MAX
];
879 for (int i
=0; i
< COL_MAX
; ++i
) colorder
[i
]=i
;
880 ListView_GetColumnOrderArray(hlist
, COL_MAX
, colorder
);
882 for (int i
=0; i
< COL_MAX
; ++i
)
884 int colw
= ListView_GetColumnWidth(hlist
, i
);
885 char buf
[256], buf2
[256];
886 sprintf(buf2
, "colwid_%d", i
);
887 sprintf(buf
, "%d", colw
);
888 char* p
= colw
== (int)COL_SIZES
[i
] ? NULL
: buf
;
889 WritePrivateProfileString("LangPackEdit", buf2
, p
, g_ini_file
.Get());
891 sprintf(buf2
, "colorder_%d", i
);
892 sprintf(buf
, "%d", colorder
[i
]);
893 p
= colorder
[i
] == i
? NULL
: buf
;
894 WritePrivateProfileString("LangPackEdit", buf2
, p
, g_ini_file
.Get());
898 g_editor
.m_hwnd
= NULL
;
900 SWELL_PostQuitMessage(0);
901 #elif defined(_WIN32)
908 if (wParam
!= SIZE_MINIMIZED
)
909 g_editor
.m_resize
.onResize();
915 KillTimer(hwndDlg
,TIMER_FILTER
);
916 g_editor
.refresh_list();
921 if (g_editor
.prompt_exit())
922 DestroyWindow(hwndDlg
);
925 switch (LOWORD(wParam
))
928 if (g_editor
.prompt_exit())
929 DestroyWindow(hwndDlg
);
932 if (HIWORD(wParam
) == EN_CHANGE
)
934 SetTimer(hwndDlg
,TIMER_FILTER
,100,NULL
);
937 case IDC_PACK_SAVE_AS
:
940 if (!g_editor
.m_pack_fn
.GetLength() || LOWORD(wParam
) == IDC_PACK_SAVE_AS
)
943 if (!WDL_ChooseFileForSave(hwndDlg
, __LOCALIZE("Save LangPack as...","langpackedit"),
945 g_editor
.m_pack_fn
.Get(),
946 "All files (*.*)\0*.*\0",
949 newfn
,sizeof(newfn
)) || !newfn
[0]) return 0;
951 g_editor
.m_pack_fn
.Set(newfn
);
952 WritePrivateProfileString("LangPackEdit","lastpack",newfn
,g_ini_file
.Get());
953 SetDlgItemText(hwndDlg
,IDC_PACK
,newfn
);
956 g_editor
.save_file(g_editor
.m_pack_fn
.Get());
957 g_editor
.m_dirty
=false;
958 g_editor
.set_caption();
962 case IDC_TEMPLATE_LOAD
:
965 const bool is_template
= LOWORD(wParam
) == IDC_TEMPLATE_LOAD
;
966 const char *inikey
= is_template
? "template" : "lastpack";
967 GetPrivateProfileString("LangPackEdit",inikey
,"",buf
,sizeof(buf
),g_ini_file
.Get());
968 char *f
= WDL_ChooseFileForOpen(hwndDlg
,
969 is_template
? __LOCALIZE("Choose LangPack Template","langpackedit") :
970 __LOCALIZE("Load LangPack","langpackedit"),
973 "All files (*.*)\0*.*\0"
979 WritePrivateProfileString("LangPackEdit",inikey
,f
,g_ini_file
.Get());
980 g_editor
.load_file(f
,is_template
);
981 if (!is_template
) g_editor
.m_pack_fn
.Set(f
);
985 g_editor
.m_dirty
=false;
986 g_editor
.set_caption();
991 case IDC_LOCALIZED_STRING
:
992 case IDC_COMMON_STRING
:
994 case IDC_COPY_TEMPLATE
:
995 case IDC_REMOVE_LOCALIZATION
:
996 case IDC_REMOVE_NONLOCALIZATION
:
998 HWND list
= GetDlgItem(hwndDlg
,IDC_LIST
);
1000 const int n
= ListView_GetItemCount(list
);
1001 for (int x
= 0; x
< n
; x
++)
1003 if (ListView_GetItemState(list
,x
,LVIS_SELECTED
) & LVIS_SELECTED
)
1005 if (g_editor
.edit_row(x
,(int)wParam
)) cnt
++;
1006 if (wParam
== ID_SCALING_ADD
)
1007 ListView_SetItemState(list
,x
,0,LVIS_SELECTED
);
1010 if (cnt
&& wParam
!= IDC_LOCALIZED_STRING
)
1012 g_editor
.refresh_list();
1013 g_editor
.set_dirty();
1015 if (wParam
== ID_SCALING_ADD
)
1017 const int nn
= ListView_GetItemCount(list
);
1020 ListView_EnsureVisible(list
,n
,false);
1021 for (int i
= n
; i
< nn
; i
++)
1022 ListView_SetItemState(list
,i
,LVIS_SELECTED
,LVIS_SELECTED
);
1029 case ID_COL_TEMPLATE
:
1030 case ID_COL_LOCALIZED
:
1031 case ID_COL_COMMONLOCALIZED
:
1032 g_editor
.m_column_no_searchflags
^= (1<<(LOWORD(wParam
) - ID_COL_STATE
));
1035 snprintf(tmp
,sizeof(tmp
),"%d",g_editor
.m_column_no_searchflags
);
1036 WritePrivateProfileString("LangPackEdit","nosearchcols",tmp
,g_ini_file
.Get());
1038 SetTimer(hwndDlg
,TIMER_FILTER
,100,NULL
);
1040 case ID_SORTCOL_STATE
:
1042 case ID_SORTCOL_TEMPLATE
:
1043 case ID_SORTCOL_LOCALIZED
:
1044 case ID_SORTCOL_COMMONLOCALIZED
:
1045 g_editor
.m_sort_rev
= false;
1046 g_editor
.m_sort_col
= LOWORD(wParam
) - ID_SORTCOL_STATE
;
1047 g_editor
.on_sort_change();
1049 case ID_SORTCOL_REVERSE
:
1050 g_editor
.m_sort_rev
= !g_editor
.m_sort_rev
;
1051 g_editor
.on_sort_change();
1055 case WM_INITMENUPOPUP
:
1058 HMENU menu
= (HMENU
) wParam
;
1059 static const unsigned short tab
[]={
1060 IDC_LOCALIZED_STRING
,
1064 IDC_REMOVE_LOCALIZATION
,
1065 IDC_REMOVE_NONLOCALIZATION
,
1067 bool en
= ListView_GetSelectedCount(GetDlgItem(hwndDlg
,IDC_LIST
))>0;
1068 for (size_t x
= 0; x
< sizeof(tab
)/sizeof(tab
[0]); x
++)
1069 EnableMenuItem(menu
,tab
[x
],MF_BYCOMMAND
|(en
? 0 : MF_GRAYED
));
1070 for (int x
= 0; x
< COL_MAX
; x
++)
1071 CheckMenuItem(menu
,ID_COL_STATE
+x
, MF_BYCOMMAND
| ((g_editor
.m_column_no_searchflags
&(1<<x
)) ? MF_UNCHECKED
:MF_CHECKED
));
1072 for (int x
= 0; x
< COL_MAX
; x
++)
1073 CheckMenuItem(menu
,ID_SORTCOL_STATE
+x
, MF_BYCOMMAND
| ((g_editor
.m_sort_col
== x
) ? MF_CHECKED
:MF_UNCHECKED
));
1074 CheckMenuItem(menu
,ID_SORTCOL_REVERSE
, MF_BYCOMMAND
| (g_editor
.m_sort_rev
? MF_CHECKED
:MF_UNCHECKED
));
1079 NMLISTVIEW
* lv
= (NMLISTVIEW
*)lParam
;
1080 if (lv
->hdr
.idFrom
== IDC_LIST
) switch (lv
->hdr
.code
)
1083 g_editor
.edit_row(lv
->iItem
);
1086 if (ListView_GetSelectedCount(lv
->hdr
.hwndFrom
)>0)
1088 g_editor
.item_context_menu();
1091 case LVN_COLUMNCLICK
:
1093 int col
= lv
->iSubItem
;
1094 if (col
== COL_ROW_IDX
) col
= COL_ID
;
1095 if (g_editor
.m_sort_col
== col
)
1097 g_editor
.m_sort_rev
= !g_editor
.m_sort_rev
;
1101 g_editor
.m_sort_rev
= false;
1102 g_editor
.m_sort_col
= col
;
1104 g_editor
.on_sort_change();
1107 case LVN_GETDISPINFO
:
1109 case LVN_GETDISPINFOW
:
1112 NMLVDISPINFO
*lpdi
= (NMLVDISPINFO
*) lParam
;
1113 if (lpdi
->item
.mask
& LVIF_TEXT
)
1115 if (lpdi
->item
.iSubItem
== COL_ROW_IDX
)
1116 snprintf(lpdi
->item
.pszText
,lpdi
->item
.cchTextMax
,"%d",lpdi
->item
.iItem
+1);
1118 lpdi
->item
.pszText
= (char*) g_editor
.get_row_value(lpdi
->item
.iItem
, lpdi
->item
.iSubItem
);
1120 if (lv
->hdr
.code
== LVN_GETDISPINFOW
)
1121 WDL_UTF8_ListViewConvertDispInfoToW(lpdi
);
1132 INT_PTR
SWELLAppMain(int msg
, INT_PTR parm1
, INT_PTR parm2
)
1136 case SWELLAPP_ONLOAD
:
1140 case SWELLAPP_LOADED
:
1143 GetModuleFileName(NULL
,buf
,sizeof(buf
));
1144 WDL_remove_filepart(buf
);
1145 lstrcatn(buf
,WDL_DIRCHAR_STR
"LangPackEdit.ini",sizeof(buf
));
1146 g_ini_file
.Set(buf
);
1148 WDL_remove_filepart(buf
);
1149 lstrcatn(buf
,WDL_DIRCHAR_STR
"LangPackEdit.LangPack",sizeof(buf
));
1152 extern bool g_debug_langpack_has_loaded
;
1153 g_debug_langpack_has_loaded
=true;
1155 WDL_LoadLanguagePack(buf
,NULL
);
1157 HWND h
=CreateDialog(NULL
,MAKEINTRESOURCE(IDD_DIALOG1
),NULL
,mainProc
);
1158 ShowWindow(h
,SW_SHOW
);
1162 HMENU menu
= LoadMenu(NULL
,MAKEINTRESOURCE(IDR_MENU1
));
1165 HMENU sm
=GetSubMenu(menu
,0);
1166 DeleteMenu(sm
,ID_QUIT
,MF_BYCOMMAND
); // remove QUIT from our file menu, since it is in the system menu on OSX
1168 // remove any trailing separators
1169 int a
= GetMenuItemCount(sm
);
1170 while (a
> 0 && GetMenuItemID(sm
,a
-1)==0) DeleteMenu(sm
,--a
,MF_BYPOSITION
);
1173 extern HMENU SWELL_app_stocksysmenu
;
1174 if (SWELL_app_stocksysmenu
) // insert the stock system menu
1176 HMENU nm
=SWELL_DuplicateMenu(SWELL_app_stocksysmenu
);
1179 MENUITEMINFO mi
={sizeof(mi
),MIIM_STATE
|MIIM_SUBMENU
|MIIM_TYPE
,MFT_STRING
,0,0,nm
,NULL
,NULL
,0,(char*)"LangPackEdit"};
1180 InsertMenuItem(menu
,0,TRUE
,&mi
);
1183 SetMenuItemModifier(menu
,IDC_TEMPLATE_LOAD
,MF_BYCOMMAND
,'T',FCONTROL
);
1184 SetMenuItemModifier(menu
,IDC_PACK_LOAD
,MF_BYCOMMAND
,'O',FCONTROL
);
1185 SetMenuItemModifier(menu
,IDC_PACK_SAVE
,MF_BYCOMMAND
,'S',FCONTROL
);
1186 SetMenuItemModifier(menu
,IDC_PACK_SAVE_AS
,MF_BYCOMMAND
,'S',FCONTROL
|FALT
);
1195 case SWELLAPP_DESTROY
:
1196 if (g_editor
.m_hwnd
) DestroyWindow(g_editor
.m_hwnd
);
1198 case SWELLAPP_SHOULDDESTROY
:
1199 return g_editor
.prompt_exit() ? 0 : 1;
1200 case SWELLAPP_ONCOMMAND
:
1201 if (g_editor
.m_hwnd
)
1202 SendMessage(g_editor
.m_hwnd
,WM_COMMAND
,parm1
,0);
1204 case SWELLAPP_PROCESSMESSAGE
:
1207 const MSG
*m
= (MSG
*)parm1
;
1208 if (m
->message
== WM_KEYDOWN
&& m
->hwnd
)
1211 if (m
->wParam
== 'Q' &&
1212 (GetAsyncKeyState(VK_CONTROL
)&0x8000) &&
1213 !(GetAsyncKeyState(VK_SHIFT
)&0x8000) &&
1214 !(GetAsyncKeyState(VK_MENU
)&0x8000))
1216 if (g_editor
.m_hwnd
)
1217 SendMessage(g_editor
.m_hwnd
,WM_COMMAND
,ID_QUIT
,0);
1221 if (g_editor
.on_key(m
->hwnd
, m
->message
, m
->wParam
, m
->lParam
))
1234 int WINAPI
WinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPSTR lpCmdLine
, int nShowCmd
)
1236 g_hInstance
= hInstance
;
1238 SWELLAppMain(SWELLAPP_ONLOAD
,0,0);
1239 SWELLAppMain(SWELLAPP_LOADED
,0,0);
1244 int vvv
= GetMessage(&msg
,NULL
,0,0);
1254 DispatchMessage(&msg
);
1257 if (SWELLAppMain(SWELLAPP_PROCESSMESSAGE
, (INT_PTR
) &msg
, 0)) continue;
1259 if (g_editor
.m_hwnd
&& IsDialogMessage(g_editor
.m_hwnd
,&msg
)) continue;
1261 TranslateMessage(&msg
);
1262 DispatchMessage(&msg
);
1265 SWELLAppMain(SWELLAPP_DESTROY
,0,0);
1274 /************** SWELL stuff ********** */
1280 const char **g_argv
;
1290 int main(int argc
, const char **argv
)
1294 SWELL_initargs(&argc
,(char***)&argv
);
1295 SWELL_Internal_PostMessage_Init();
1296 SWELL_ExtendedAPI("APPNAME",(void*)"LangPackEdit");
1297 SWELLAppMain(SWELLAPP_ONLOAD
,0,0);
1298 SWELLAppMain(SWELLAPP_LOADED
,0,0);
1300 SWELL_RunMessageLoop();
1303 SWELLAppMain(SWELLAPP_DESTROY
,0,0);
1310 #include "../../swell/swell-dlggen.h"
1311 #include "res.rc_mac_dlg"
1314 #include "../../swell/swell-menugen.h"
1315 #include "res.rc_mac_menu"