// SKKの変換
//
//
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <ctype.h>
#include <unistd.h>
#ifndef __GNUC__
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
#endif
#include "skkconv.h"
#include "skk.xpm"
// SKK classes
// SKKConv
// SKKStat
// SKKChildContext
// SKKChildWindow
// SKKContext
// SKKDic
// SKKContext -- SKKStat
// |
// SKKChildWindow -- SKKChildContext --SKKStat
// | ..
// -- SKKChildContext -- SKKStat
//input mode
#define INPUT_MODE_RAW 0
#define INPUT_MODE_HIRA 1
#define INPUT_MODE_KATA 2
#define INPUT_MODE_WIDE 3
atom_t A_skk_share_dic;
atom_t A_skk_personal_dic;
atom_t A_skk_learn_dic;
atom_t A_skk_widelatin_mode;
atom_t A_skk_toggle_hirakata;
atom_t A_skk_begin_latin_conv;
void init_preconf_kkconv()
{
}
bool init_conv()
{
SKKConv *skk = new SKKConv();
skk->init();
register_kkconv(skk);
return true;
}
KKContext *SKKConv::createContext(XimIC *ic)
{
return new SKKContext(this,ic);
}
char *SKKConv::getModeName(int num)
{
switch (num) {
case INPUT_MODE_RAW: return "a";
case INPUT_MODE_HIRA: return "あ";
case INPUT_MODE_KATA: return "ア";
case INPUT_MODE_WIDE: return "A";
}
return NULL;
}
SKKConv::~SKKConv()
{
delete dic;
delete hira_map;
delete kata_map;
}
void SKKConv::init()
{
hira_map = new RKMap(hiragana);
kata_map = new RKMap(katakana);
A_skk_share_dic = get_atom_by_name("SkkShareDic");
A_skk_personal_dic = get_atom_by_name("SkkPersonalDic");
A_skk_learn_dic = get_atom_by_name("SkkLearnDic");
A_skk_widelatin_mode = get_atom_by_name("skk_widelatin_mode");
A_skk_toggle_hirakata = get_atom_by_name("skk_toggle_hira_kata");
A_skk_begin_latin_conv = get_atom_by_name("skk_begin_latin_conv");
dic = createSKKDic();
bind_str_to_atom("S-L", A_skk_widelatin_mode);
bind_str_to_atom("q", A_skk_toggle_hirakata);
bind_str_to_atom("slash", A_skk_begin_latin_conv);
}
char **SKKConv::getIcon()
{
return skk_xpm;
}
void SKKConv::onPushIcon()
{
}
RKMap *SKKConv::get_map(int mode)
{
if (mode == INPUT_MODE_KATA) {
return kata_map;
}
return hira_map;
}
SKKDic *SKKConv::get_dic()
{
return dic;
}
//
//
//
SKKStat::~SKKStat()
{
delete rkConv;
}
void SKKStat::init(SKKConv *c)
{
conv = c;
dic = c->get_dic();
rkConv = new RKConv();
mode = INPUT_MODE_RAW;
cands = 0;
this->flush();
}
void SKKStat::flush()
{
rkConv->flush();
convstat = STATE_DIRECT;
erase_jstring(&head);
erase_jstring(&okuri);
okuri_head = 0;
if (cands) {
delete cands;
cands = 0;
}
}
void SKKStat::setMode(int m)
{
if (mode == m) {
return ;
}
mode = m;
if (mode != INPUT_MODE_RAW) {
rkConv->flush();
rkConv->select_map(conv->get_map(mode));
}
this->flush();
}
int SKKStat::proc_key(keyState *k)
{
if (convstat == STATE_DIRECT) {
return proc_no_conv(k);
}
return proc_conv(k);
}
int SKKStat::proc_conv(keyState *k)
{
int commit_mask = SKK_UPDATE_PREEDIT;
switch(convstat){
case STATE_KANJI:
commit_mask|= proc_kanji_state(k);
break;
case STATE_OKURI:
commit_mask|= proc_okuri_state(k);
break;
case STATE_CONVERTING:
commit_mask|= proc_converting_state(k);
break;
case STATE_WAITING:
return SKK_FORWARD_CHILD;
break;
case STATE_LATIN:
commit_mask|=proc_latin_state(k);
break;
}// switch
return commit_mask;
}
int SKKStat::proc_kanji_state(keyState *k)
{
//shiftが押されたので送りがなモード
if (k->modifier(SHIFT_KEY) &&k->is_alpha() && head.size()) {
okuri_head = k->to_lower();
erase_jstring(&okuri);
convstat = STATE_OKURI;
return proc_conv(k);
}
//spaceが押されたので変換を行う
if (k->is_bind_to(A_do_conv) && head.size() > 0) {
return do_conv();
}
if (k->is_bind_to(A_skk_toggle_hirakata)) {
jstring_t *s= new jstring_t();
hirakana_conv(s, &head);
pending = s;
flush();
return SKK_COMMIT_PENDING;
}
if (k->is_bind_to(A_cancel)) {
this->flush();
return 0;
}
if (k->is_bind_to(A_delete_back)) {
if (!rkConv->back_space()) {
if (head.size()) {
head.pop_back();
}
}
return 0;
}
if (rkConv->push_key(k->to_lower())) {
cchar ch;
ch = rkConv->get_cchar();
while (ch){
head.push_back(ch);
ch = rkConv->get_cchar();
}
} else {
head.push_back(k->char_code());
}
return 0;
}
int SKKStat::proc_okuri_state(keyState *k)
{
if (k->is_bind_to(A_cancel)) {
if (rkConv->is_pending()) {
rkConv->flush();
return 0;
} else {
this->flush();
return 0;
}
}
if (!rkConv->push_key(k->to_lower())) {
return 0;
}
cchar ch;
ch = rkConv->get_cchar();
if (!ch) {
return 0;
}
while (ch) {
okuri.push_back(ch);
ch = rkConv->get_cchar();
}
cands = dic->getCandidates(this);
if (cands) {
convstat = STATE_CONVERTING;
} else {
convstat = STATE_WAITING;
return SKK_CREATE_CCONTEXT;
}
return 0;
}
int SKKStat::proc_converting_state(keyState *k)
{
int r;
jstring_t s;
r = cands->proc_key(k, &s);
if (r & CAND_EXHAUST) {
convstat = STATE_WAITING;
return SKK_CREATE_CCONTEXT;
}
if (r & CAND_CANCEL) {
cancel();
return 0;
}
if (r & CAND_COMMIT) {
dic->commit(this, &s);
jstring_t *ss= new jstring_t();
append_jstring(ss, &cands->cands[cands->nth]);
append_jstring(ss, &okuri);
pending = ss;
flush();
delete cands;
cands = 0;
if (k->is_bind_to(A_commit)) {
return SKK_COMMIT_PENDING;
}
return PUSHKEY_AGAIN |SKK_COMMIT_PENDING;
}
return 0;
}
int SKKStat::proc_latin_state(keyState *k)
{
if (k->is_bind_to(A_cancel)) {
flush();
return 0;
}
if (k->is_bind_to(A_delete_back)) {
if (head.size() > 0) {
head.pop_back();
return 0;
}
flush();
return COMMIT_RAW;
}
int cc = k->char_code();
if (cc > 32 && cc != ' ' && cc < 128) {
head.push_back(k->char_code());
return 0;
}
if (k->is_bind_to(A_do_conv) && head.size() > 0) {
return do_conv();
}
jstring_t *s;
s = new jstring_t();
append_jstring(s, &head);
pending = s;
flush();
if (k->is_bind_to(A_commit)) {
return SKK_COMMIT_PENDING;
}
return PUSHKEY_AGAIN |SKK_COMMIT_PENDING;
}
int SKKStat::proc_no_conv(keyState *k)
{
// XXX そのうち統一
if (mode == INPUT_MODE_RAW) {
return proc_raw_mode(k);
}
if (mode == INPUT_MODE_WIDE) {
return proc_wide_mode(k);
}
if (k->is_bind_to(A_latin_mode)) {
mode = INPUT_MODE_RAW;
rkConv->flush();
return UPDATE_MODE | SKK_UPDATE_PREEDIT;
}
if (k->is_bind_to(A_skk_widelatin_mode)) {
mode = INPUT_MODE_WIDE;
rkConv->flush();
return UPDATE_MODE | SKK_UPDATE_PREEDIT;
}
if (k->is_bind_to(A_skk_begin_latin_conv)) {
this->flush();
convstat = STATE_LATIN;
return SKK_UPDATE_PREEDIT;
}
if (rkConv->is_pending()) {
if (k->is_bind_to(A_cancel)) {
rkConv->flush();
return SKK_UPDATE_PREEDIT;
} else if ( k->is_bind_to(A_delete_back)) {
rkConv->back_space();
return SKK_UPDATE_PREEDIT;
}
} else if (k->is_bind_to(A_cancel)) {
return COMMIT_RAW;
}
if (k->is_bind_to(A_skk_toggle_hirakata)) {
if (mode == INPUT_MODE_HIRA) {
mode = INPUT_MODE_KATA;
} else {
mode = INPUT_MODE_HIRA;
}
rkConv->select_map(conv->get_map(mode));
rkConv->flush();
return UPDATE_MODE|SKK_UPDATE_PREEDIT;
}
if (!rkConv->push_key(k->to_lower())) {
// 入力が取り込まれなかった。
return COMMIT_RAW|SKK_UPDATE_PREEDIT;
}
cchar ch;
ch = rkConv->get_cchar();
// shift とアルファベットにより変換開始
if (k->modifier(SHIFT_KEY) && k->is_alpha()) {
erase_jstring(&head);
erase_jstring(&okuri);
convstat = STATE_KANJI;
if (ch) {
head.push_back(ch);
}
return DO_NOTHING | SKK_UPDATE_PREEDIT;
}
if (!ch) {
return DO_NOTHING | SKK_UPDATE_PREEDIT;
}
//普通の平仮名か片仮名のコミット
jstring_t *sy = new jstring_t();
do {
sy->push_back(ch);
ch = rkConv->get_cchar();
} while (ch);
pending = sy;
return SKK_COMMIT_PENDING | SKK_UPDATE_PREEDIT;
}
int SKKStat::proc_raw_mode(keyState *k)
{
if (k->is_bind_to(A_hira_mode)) {
mode = INPUT_MODE_HIRA;
rkConv->select_map(conv->get_map(mode));
rkConv->flush();
return UPDATE_MODE;
}
return COMMIT_RAW;
}
int SKKStat::proc_wide_mode(keyState *k)
{
if (k->is_bind_to(A_commit)) {
mode = INPUT_MODE_HIRA;
rkConv->select_map(conv->get_map(mode));
rkConv->flush();
return UPDATE_MODE;
}
return COMMIT_WIDE;
}
int SKKStat::do_conv()
{
cands = dic->getCandidates(this);
if (cands) {
convstat = STATE_CONVERTING;
}else{
convstat = STATE_WAITING;
return SKK_CREATE_CCONTEXT;
}
return 0;
}
void SKKStat::cancel()
{
if (cands) {
delete cands;
cands = 0;
}
append_jstring(&head, &okuri);
erase_jstring(&okuri);
okuri_head = 0;
convstat = STATE_KANJI;
}
//
//
//
SKKContext::SKKContext(SKKConv *c, XimIC *ic) : KKContext(ic)
{
mStat.init(c);
m_child = 0;
}
SKKContext::~SKKContext()
{
if (m_child) {
delete m_child;
}
}
void SKKContext::OnUpdatePe(pe_stat *pe)
{
pe->clear();
if (mStat.mode == INPUT_MODE_RAW) {
return ;
}
pe->new_segment(PE_UNDERLINE);
switch (mStat.convstat) {
case STATE_DIRECT:
{
// ローマ字に変換されてないものを表示する。
char buf[10];
if (mStat.rkConv->get_pending_char(buf, 10)) {
int l = strlen(buf),i;
for (i = 0; i < l; i++) {
pe->push_cchar(buf[i]);
}
}
break;
}
case STATE_KANJI:
case STATE_OKURI:
case STATE_LATIN:
{
// 途中を入力中
pe->push_cchar(0x2260);//▽0x2226
pe->new_segment(PE_UNDERLINE);
jstring_t::iterator i;
for (i = mStat.head.begin(); i != mStat.head.end(); i++) {
pe->push_cchar(*i);
}
if (mStat.convstat == STATE_OKURI) {
pe->push_cchar('*');
}
char buf[10];
if (mStat.rkConv->get_pending_char(buf, 10)) {
int i, l= strlen(buf);
for (i = 0; i < l; i++) {
pe->push_cchar(buf[i]);
}
}
break;
}
case STATE_CONVERTING:
{
pe->new_segment(PE_REVERSE);
if (mStat.cands->opCount > 3) {
pe->cands = mStat.cands;
} else {
pe->cands = 0;
}
}
case STATE_WAITING:
{
pe->push_cchar(0x2260);//▼0x2227
pe->new_segment(PE_REVERSE);
jstring_t::iterator i;
jstring_t *s = 0;
if (mStat.convstat == STATE_WAITING) {
s = &mStat.head;
} else {
s = &(mStat.cands->cands[mStat.cands->nth]);
}
for (i = s->begin(); i != s->end(); i++) {
pe->push_cchar(*i);
}
pe->new_segment(PE_REVERSE);
for (i = mStat.okuri.begin(); i != mStat.okuri.end(); i++) {
pe->push_cchar(*i);
}
break;
}
}//switch
}
int SKKContext::pushKey(keyState *k)
{
int res=0;
res = mStat.proc_key (k);
if (res & SKK_UPDATE_PREEDIT) {
update_preedit ();
}
if (res & SKK_COMMIT_PENDING) {
commit_jstring (mStat.pending);
delete mStat.pending;
mStat.pending = 0;
}
if (res & SKK_CREATE_CCONTEXT) {
create_child_context ();
}
if ((res & SKK_FORWARD_CHILD) && m_child) {
int r;
r = m_child->pushKey(k);
}
return res & KK_PUSHKEY_MASK;
}
int SKKContext::getMode()
{
return mStat.mode;
}
void SKKContext::setMode(int m)
{
mStat.setMode(m);
}
void SKKContext::candidate_selected(int n)
{
commit_jstring(&(mStat.cands->cands[n]));
mStat.flush();
delete mStat.cands;
mStat.cands = 0;
update_preedit();
}
bool SKKContext::extra_input(jstring_t *s)
{
if (mStat.convstat == STATE_WAITING) {
return m_child->extra_input(s);
}
return false;
}
jstring_t *SKKContext::clear()
{
mStat.flush();
if (m_child) {
m_child->close();
}
return 0;
}
//再帰学習のためのWindowを作る
void SKKContext::create_child_context()
{
if (!m_child) {
m_child = new SKKChildWindow(mStat.conv, this);
}
m_child->open(&mStat);
}
//再帰学習のためのWindowが閉じるときに呼ばれる
void SKKContext::commit_child(jstring_t *s)
{
mStat.dic->commit(&mStat, s);
commit_jstring(s);
mStat.flush();
}
void SKKContext::cancel_child()
{
mStat.cancel();
update_preedit();
}
//
//
SKKChildContext::SKKChildContext(SKKConv *c, SKKChildContext *p, SKKStat *s)
{
stat.init(c);
init();
parent_context = p;
learn = s->head;
if (s->okuri.size()) {
learn.push_back('*');
append_jstring(&learn, &s->okuri);
if (s->okuri_head) {
learn.push_back('(');
learn.push_back(s->okuri_head);
learn.push_back(')');
}
}
char buf[16];
sprintf(buf, ":%d", get_current_level());
int i;
for (i = 0; i < (int)strlen( buf ); i++) {
learn.push_back(buf[i]);
}
}
SKKChildContext *SKKChildContext::get_parent_context()
{
return parent_context;
}
void SKKChildContext::cancel_child()
{
stat.flush();
}
void SKKChildContext::commit_child(jstring_t *s)
{
stat.flush();
append_jstring(&pre, s);
}
int SKKChildContext::pushKey(keyState *k)
{
int res;
res = stat.proc_key(k);
if (res & SKK_COMMIT_PENDING) {
append_jstring(&pre, stat.pending);
delete stat.pending;
stat.pending = 0;
res &= (~SKK_COMMIT_PENDING);
}
if (res & (COMMIT_RAW|COMMIT_WIDE)) {
res = proc_edit_key(k, res);
}
return res;
}
int SKKChildContext::get_current_level()
{
if (parent_context) {
return parent_context->get_current_level()+1;
}
return 1;
}
int SKKChildContext::proc_edit_key(keyState *k, int res)
{
// テキストコントロールの操作を処理する
if (k->is_bind_to(A_delete_back)) {
if (pre.size() > 0) {
pre.pop_back();
res |= SKK_UPDATE_PREEDIT;
}
} else if (k->is_bind_to(A_go_left)) {
if (pre.size() > 0) {
cchar c = *(pre.rbegin());
pre.pop_back();
post.push_front(c);
res |= SKK_UPDATE_PREEDIT;
}
} else if (k->is_bind_to(A_go_right)) {
if (post.size() > 0) {
cchar c = *(post.begin());
post.pop_front();
pre.push_back(c);
res |= SKK_UPDATE_PREEDIT;
}
} else if(k->is_bind_to(A_delete_here)) {
if (post.size() > 0) {
post.pop_front();
res |= SKK_UPDATE_PREEDIT;
}
} else if (k->is_bind_to(A_cancel)) {
res |= (SKK_UPDATE_PREEDIT | SKK_CANCEL_CHILD);
} else if (k->is_bind_to(A_go_line_head)) {
append_jstring(&pre, &post);
post = pre;
erase_jstring(&pre);
res |= SKK_UPDATE_PREEDIT;
} else if (k->is_bind_to(A_go_line_end)) {
append_jstring(&pre, &post);
erase_jstring(&post);
res |= SKK_UPDATE_PREEDIT;
} else if (k->is_bind_to(A_return)) {
res |= SKK_COMMIT_PENDING;
} else if (k->is_bind_to(A_delete_right)) {
copy_to_global_buffer(&post);
erase_jstring(&post);
// グローバルなカットバッファに入れる?
res |= SKK_UPDATE_PREEDIT;
} else {
cchar c = k->char_code();
if (c) {
if (res & COMMIT_WIDE) {
c = ascii_to_wide(c);
}
pre.push_back(c);
res |= SKK_UPDATE_PREEDIT;
}
}
return res;
}
void SKKChildContext::init()
{
stat.setMode(INPUT_MODE_HIRA);
erase_jstring(&pre);
erase_jstring(&post);
}
bool SKKChildContext::extra_input(jstring_t *s)
{
if (stat.convstat == STATE_DIRECT) {
append_jstring(&pre, s);
return true;
}
return false;
}
//
SKKChildWindow::SKKChildWindow(SKKConv *conv, SKKContext *cont)
{
init_win();
set_current_context(0);
m_skkConv = conv;
m_skkContext = cont;
}
SKKChildWindow::~SKKChildWindow()
{
close();
gtk_widget_destroy(m_win);
}
void SKKChildWindow::open(SKKStat *s)
{
set_current_context(new SKKChildContext(m_skkConv, 0, s));
gtk_widget_show(m_win);
draw_text_entry();
update_mode();
}
void SKKChildWindow::close()
{
SKKChildContext *c, *d;
while ((c = get_current_context())) {
d = c->get_parent_context();
delete c;
set_current_context(d);
}
}
void SKKChildWindow::init_win()
{
GtkWidget *table;
m_pix = 0;
m_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_usize(m_win, 600, 100);
gtk_window_set_title(GTK_WINDOW(m_win), "heke(skk)");
add_widget_watch(m_win, WIDGET_KEY_PRESS, this);
table = gtk_table_new(5, 30, TRUE);
gtk_container_add(GTK_CONTAINER(m_win), table);
m_text = gtk_drawing_area_new();
gtk_table_attach_defaults(GTK_TABLE(table), m_text, 7, 23, 1, 4);
add_widget_watch(m_text,WIDGET_EXPOSE, this);
add_widget_watch(m_text,WIDGET_RESIZE, this);
gtk_widget_show(m_text);
m_commit_button = gtk_button_new_with_label("確定");
gtk_table_attach_defaults(GTK_TABLE(table), m_commit_button, 24, 29, 1, 2);
gtk_widget_show(m_commit_button);
add_widget_watch(m_commit_button, WIDGET_CLICK, this);
m_cancel_button = gtk_button_new_with_label("キャンセル");
gtk_table_attach_defaults(GTK_TABLE(table), m_cancel_button, 24, 29, 3, 4);
gtk_widget_show(m_cancel_button);
add_widget_watch(m_cancel_button, WIDGET_CLICK,this);
m_stat_menu = gtk_option_menu_new();
GtkWidget *menu;
menu = gtk_menu_new();
add_input_mode(menu,"raw", INPUT_MODE_RAW);
add_input_mode(menu,"ひらがな", INPUT_MODE_HIRA);
add_input_mode(menu,"カタカナ", INPUT_MODE_KATA);
add_input_mode(menu,"Wide", INPUT_MODE_WIDE);
gtk_option_menu_set_menu(GTK_OPTION_MENU(m_stat_menu), menu);
gtk_table_attach_defaults(GTK_TABLE(table), m_stat_menu, 1, 6, 2, 4);
gtk_widget_show(menu);
gtk_widget_show(m_stat_menu);
gtk_widget_show(table);
}
void SKKChildWindow::add_input_mode(GtkWidget *menu, char *name, int mode)
{
GtkWidget *menu_item;
menu_item = gtk_menu_item_new_with_label(name);
gtk_menu_append(GTK_MENU (menu), menu_item);
add_widget_watch(menu_item, WIDGET_ACTIVATE, this, (void *)mode);
gtk_widget_show(menu_item);
}
void SKKChildWindow::key_press(GtkWidget *w, GdkEventKey *e)
{
keyState k(e);
if (!k.is_modifier()) {
pushKey(&k);
}
}
int SKKChildWindow::pushKey(keyState *k)
{
// この関数はSKKの学習Windowに対する直接のキーイベントと
// 入力ウィンドウからフォワードされてきたキーイベントの
// 両方を受けとる。
int res;
SKKChildContext *cc = get_current_context ();
res = cc->pushKey (k);
if (res & SKK_UPDATE_PREEDIT) {
draw_text_entry ();
}
if (res & UPDATE_MODE) {
update_mode ();
}
if (res & SKK_CREATE_CCONTEXT) {
SKKChildContext *new_cont;
new_cont = new SKKChildContext (m_skkConv, cc, &cc->stat);
set_current_context (new_cont);
draw_text_entry ();
}
if (res & SKK_CANCEL_CHILD) {
cancel_current ();
return res;
}
if (res & SKK_COMMIT_PENDING) {
commit_to_parent ();
return res;
}
return res;
}
void SKKChildWindow::resize(GtkWidget *g, int w, int h)
{
if (m_pix) {
gdk_pixmap_unref(m_pix);
}
m_pix = gdk_pixmap_new(g->window, w, h, -1);
clear_preedit();
draw_text_entry();
draw();
}
void SKKChildWindow::expose(GtkWidget *g)
{
if (!m_pix) {
resize(g, g->allocation.width, g->allocation.height);
}
draw();
}
void SKKChildWindow::clicked(GtkWidget *w)
{
if (w == m_commit_button) {
commit_to_parent();
} else if (w == m_cancel_button) {
cancel_current();
}
}
void SKKChildWindow::draw()
{
gdk_draw_pixmap(m_text->window,
m_text->style->fg_gc[GTK_WIDGET_STATE(m_text)],
m_pix,
0, 0, 0, 0,
m_text->allocation.width, m_text->allocation.height);
}
void SKKChildWindow::activate(GtkWidget *w, gpointer p)
{
SKKChildContext *c;
int pos = (int)p;
c = get_current_context();
if (c) {
c->stat.setMode(pos);
}
}
void SKKChildWindow::clear_preedit()
{
gdk_draw_rectangle(m_pix,m_text->style->white_gc,
TRUE, 0, 0,
m_text->allocation.width,
m_text->allocation.height);
}
void SKKChildWindow::draw_text_entry()
{
int x=0;
jstring_t::iterator i;
SKKChildContext *c = get_current_context();
clear_preedit();
for (i = c->pre.begin(); i != c->pre.end(); i++) {
x = draw_cchar(*i, x, 1, 0);
}
x = draw_preedit(x);
x = draw_cchar('|', x, 1, 0); // カーソルのつもり
for (i = c->post.begin(); i != c->post.end(); i++) {
x = draw_cchar(*i, x, 1, 0);
}
// 変換元のやつを描画
int p = 20;
for (i = c->learn.begin(); i != c->learn.end(); i++) {
p = draw_cchar(*i, p, 0, 0);
}
draw();
}
//text field中のSKKによる編集中の部分を書く
int SKKChildWindow::draw_preedit(int x)
{
// この関数はSKKContext::OnUpdatePeとほとんど同じ
// なんとかできないものか
jstring_t::iterator i;
SKKChildContext *c= get_current_context();
switch (c->stat.convstat ) {
case STATE_DIRECT:
{
char buf[10];
if (c->stat.rkConv->get_pending_char(buf, 10)) {
int l = strlen(buf), j;
for (j = 0; j < l; j++) {
x = draw_cchar(buf[j], x, 1, 0);
}
}
}
break;
case STATE_KANJI:
case STATE_OKURI:
case STATE_LATIN:
{
x = draw_cchar(0x2226, x, 1, 0);
for (i = c->stat.head.begin();
i != c->stat.head.end(); i++) {
x = draw_cchar(*i, x, 1, 0);
}
if (c->stat.convstat == STATE_OKURI) {
x = draw_cchar('*', x, 1, 0);
}
char buf[10];
if (c->stat.rkConv->get_pending_char(buf, 10)) {
int i, l = strlen(buf);
for (i = 0; i < l; i++) {
x = draw_cchar(buf[i], x, 1, 0);
}
}
}
break;
case STATE_CONVERTING:
{
// XXX 候補Windowを出してない
x = draw_cchar(0x2227, x, 1, 0);
jstring_t *s = &(c->stat.cands->cands[c->stat.cands->nth]);
for(i = s->begin(); i != s->end(); i ++) {
x = draw_cchar(*i, x, 1, 0);
}
for (i = c->stat.okuri.begin(); i!= c->stat.okuri.end()
; i++) {
x = draw_cchar(*i, x, 1, 0);
}
}
break;
}
return x;
}
int SKKChildWindow::draw_cchar(cchar c, int x, int y, int m)
{
char buf[3];
buf[2] = 0;
if (c < 256) {
buf[0] = c;
buf[1] = 0;
}else {
buf[0] = ((c>>8)& 0xff) | 0x80;
buf[1] = (c & 0xff) | 0x80;
}
gdk_draw_string(m_pix, m_text->style->font, m_text->style->black_gc,
x, 20 + y*20, buf);
x += gdk_string_width(m_text->style->font, buf);
return x;
}
SKKChildContext *SKKChildWindow::get_current_context()
{
return m_context;
}
void SKKChildWindow::set_current_context(SKKChildContext *c)
{
m_context = c;
}
void SKKChildWindow::commit_to_parent()
{
SKKChildContext *cc, *pc;
cc = get_current_context();
pc = cc->get_parent_context();
jstring_t s;
append_jstring(&s, &cc->pre);
append_jstring(&s, &cc->post);
if (!pc) {
gtk_widget_hide(m_win);
m_skkContext->commit_child(&s);
delete cc;
set_current_context(0);
} else {
pc->commit_child(&s);
delete cc;
set_current_context(pc);
draw_text_entry();
}
}
void SKKChildWindow::cancel_current()
{
SKKChildContext *cc, *pc;
cc = get_current_context();
pc = cc->get_parent_context();
if (pc) {
pc->cancel_child();
delete cc;
set_current_context(pc);
draw_text_entry();
} else {
gtk_widget_hide(m_win);
delete cc;
set_current_context(0);
m_skkContext->cancel_child();
}
}
bool SKKChildWindow::extra_input(jstring_t *s)
{
SKKChildContext *c;
c = get_current_context();
if (c->extra_input(s)) {
draw_text_entry();
return true;
}
return false;
}
void SKKChildWindow::update_mode()
{
SKKChildContext *c;
c = get_current_context();
int m = c->stat.mode;
gtk_option_menu_set_history(GTK_OPTION_MENU(m_stat_menu), m - 1);
gtk_widget_draw(m_stat_menu, NULL);
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1