import runtime
import widget
import uiconfig
from cursor import Cursor
import status
import utils
import config
def pop(list):
try:
return list.pop()
except IndexError:
return None
SI = chr(15)
SO = chr(14)
TAG_TEXT = '%stext%s' % (SI, SO)
TAG_IMAGE = '%simg%s' % (SI, SO)
TAG_NEWLINE = '%snl%s' % (SI, SO)
class RichTextOverflowError(Exception):
pass
class RichTextObject(object):
def __init__(self, parent):
self._parent = parent
self._widget = None
self.dirty = True
self.private = None
self.geom_cache = 0,0,0,0
self.hiddenset = 0
def set_private_data(self, d):
self.private = d
def get_private_data(self):
return self.private
def get_data(self):
return (self.tag(), self.get_text(), self.get_private_data())
def free(self):
self.hide()
self._parent = None
if self._widget:
self._widget.free()
def show(self):
if self.hiddenset == 1:
'''
if self._widget:
ShowWidget = self._widget
t = unicode('')
if len(ShowWidget.text) > 0:
i = 0
while( i < (len(ShowWidget.text)-1) ):
t += unicode('*')
i += 1
t += ShowWidget.text[-1:]
ShowWidget.text = t
ShowWidget.show()
'''
if self._widget:
print 'yaaaa:self._widget.text=', self._widget.text
if status.RichTextFocus != 1:
if status.prev_tc != None:
status.prev_tc.hide()
status.prev_tc.free()
status.prev_tc = None
if status.prev_tc_box != None:
status.prev_tc_box.hide()
status.prev_tc_box.free()
status.prev_tc_box = None
if self._widget.text[-1:] != '*' and status.RichTextFocus == 1:
if status.prev_tc != None:
status.prev_tc.hide()
status.prev_tc.free()
status.prev_tc = None
if status.prev_tc_box != None:
status.prev_tc_box.hide()
status.prev_tc_box.free()
status.prev_tc_box = None
if status.crnt_key != config.CLEAR:
tc_box = utils.put_image('/usr/local/lgvp/images/pwchar.png',(143, self._widget.pos[1]-2))
tc_box.show()
status.prev_tc_box = tc_box
tc = runtime.evas.text()
tc.font=self._parent._text_font
tc.color=self._parent._text_color
tc.text= self._widget.text[-1:]
tc.pos =(151, self._widget.pos[1])
tc.show()
status.prev_tc = tc
ShowWidget = self._widget
t = unicode('')
if len(ShowWidget.text) > 0:
i = 0
while( i < len(ShowWidget.text) ):
t += unicode('*')
i += 1
ShowWidget.text = t
ShowWidget.show()
'''
CharWidget = self._widget
print 'self._widget.pos=', self._widget.pos
CharWidget.pos = (self._widget.pos[0] - 30, self._widget.pos[1])
print 'CharWidget.pos =', CharWidget.pos
#CharWidget.text = self._widget.text[-1:]
CharWidget.text = '1234567890'
CharWidget.show()
'''
else:
if self._widget: self._widget.show()
def hide(self):
if self._widget: self._widget.hide()
def x(self):
return self.geom_cache[0]
def y(self):
return self.geom_cache[1]
def width(self, length=-1):
return self.geom_cache[2]
def height(self):
return self.geom_cache[3]
def move(self, x, y):
if self._widget:
self._widget.move(x,y)
self.geom_cache = self._widget.geometry_get()
def dup(self):
pass
def set_text(self, data):
pass
def get_text(self):
pass
def render(self):
pass
def set_clip(self, clip):
if self._widget: self._widget.clip_set(clip)
# return newly created object or False
def split(self, width, force = False):
return False
def split_in_length(self, len):
return False
# return True or False
def join(self, o):
return False
def message_length(self):
return self.length()
def length(self):
return 1
def cut(self, index, length):
return False
class RichTextObject_NewLine(RichTextObject):
def __init__(self, parent):
RichTextObject.__init__(self, parent)
self._ul = None
def tag(self):
return TAG_NEWLINE
def move(self, x, y):
self.geom_cache = (x,y,0,16)
def get_text(self):
return '\n'
class RichTextObject_Text(RichTextObject):
def __init__(self, parent, hiddenset = 0):
RichTextObject.__init__(self, parent)
self.dirty = True
self._widget = runtime.evas.text()
self._widget.font = parent._text_font
self._widget.color = parent._text_color
self._descent = self._widget.descent_get()
self._ul = None
self._add_word_rect = None
self._text = unicode('')
self.hiddenset = hiddenset
def tag(self):
return TAG_TEXT
def move(self, x,y ):
RichTextObject.move(self,x,y)
if self._ul:
self.update_ul()
def free(self):
if self._ul: self._ul.free()
if self._add_word_rect: self._add_word_rect.free()
RichTextObject.free(self)
def hide(self):
if self._ul: self._ul.hide()
if self._add_word_rect: self._add_word_rect.hide()
RichTextObject.hide(self)
def show(self):
self.update_ul()
RichTextObject.show(self)
def enable_ul(self, ul):
if (self._ul and ul) or (not self._ul and not ul):
return
if ul:
if not self._ul:
self._ul = runtime.evas.rectangle()
self._ul.color = uiconfig.edit_underline_color
else:
if self._ul:
self._ul.free()
self._ul = None
if status.password_style:
self._parent.formatting()
def update_ul(self):
if not self._ul:
return
x1 = self.x()
x2 = self.x() + self.width()
y1 = self.y()
y2 = y1 + self.height()
if self._parent._ul_shape == 'rectangle':
self._widget.color = uiconfig.edit_invert_color
self._widget.layer_set(100)
if not self._add_word_rect:
self._add_word_rect = runtime.evas.rectangle()
self._add_word_rect.layer_set(99)
self._add_word_rect.color = uiconfig.edit_underline_rect_color
self._add_word_rect.move(x1, y1)
self._add_word_rect.resize(x2-x1, y2 - y1)
self._add_word_rect.show()
self._ul.color = uiconfig.edit_underline_invert_color
self._ul.move(x1, y2 - self._descent)
self._ul.resize(x2-x1, 1)
self._ul.layer_set(100)
elif self._parent._ul_shape == 'line':
self._widget.color = uiconfig.edit_color
if self._add_word_rect:
self._add_word_rect.free()
self._add_word_rect = None
self._ul.color = uiconfig.edit_underline_color
self._ul.move(x1, y2 - self._descent)
self._ul.resize(x2-x1, 1)
else:
pass
#print 'Unknown shape [%s]' % self._parent._ul_shape
#assert False
if self._parent.clip:
self._ul.clip_set(self._parent.clip)
# KA: [20070831] hangul lvp-2000
#self._ul.show()
def set_text(self, data):
self._text = data
self._widget.text_set(self._text)
self.geom_cache = self._widget.geometry_get()
self.dirty = True
def get_text(self):
return self._text
def get_last_character(self):
return self._text[-1:]
def width(self, length=-1):
if length < 0:
return self._widget.horiz_advance_get()
elif length == 0:
return 0
else:
t = runtime.evas.text()
t.font = self._widget.font_get()
t.text_set(self._text[:length])
width = t.horiz_advance_get()
t.free()
return width
def dup(self):
o = RichTextObject_Text(self._parent)
o._widget.text_set(self._text)
name, size = self._widget.font_get()
o._widget.font_set(name,size)
r,g,b,a = self._widget.color_get()
o._widget.color_set(r,g,b,a)
clip = self._widget.clip_get()
if clip: o._widget.clip_set(clip)
if self._ul: o.enable_ul(True)
o._widget.layer_set(self._widget.layer_get())
o.move(self.x(), self.y())
return o
# force
# * True: split in byte
# * False: split in word
def split(self, base_x, width, force = False):
if width == 0:
width = base_x
#assert width > 0
rc = self._widget.char_coords_get(width, 0)
split_pos = rc[0]
if split_pos == 0:
return None
if split_pos < 0 or split_pos >= len(self._text):
# 글자폭 계산을 horiz_advance_get()으로 하기 때문에
# 실제 글자가 없는 위치에서도 자를려고 할 때가 있다.
# work-around로 마지막 글자에 위치하도록 수정
split_pos = len(self._text) - 1
if not force and split_pos > 0:
if self._text[split_pos-1] != ' ':
split_pos = self._text[:split_pos].rfind(' ')
if split_pos <= 0:
# can't split
return None
# the space will be included in the first one that is splitted
split_pos += 1
text = self._text
self.set_text(self._text[:split_pos])
self.geom_cache = self._widget.geometry_get()
while self.width() >= width and split_pos > 0:
split_pos -= 1
self.set_text(text[:split_pos])
self.geom_cache = self._widget.geometry_get()
o = self.dup()
o.set_text(text[split_pos:])
self.dirty = True
return o
#중간에 값을 입력하면 그곳에 데이타를 삽입하기 위하여 그 커서 위치의 앞의 text를 바꾸고 뒤의 글자는 새로운 오브젝트로 등록한다
#만약 뒷글자가 없으면 아무런 동작을 하지 않는다
def split_in_length(self, length):
#assert length > 0
#assert length < len(self._text)
t1 = self._text[:length]
t2 = self._text[length:]
if not t2:
return None
self.set_text(t1)
o = self.dup()
o.set_text(t2)
self.dirty = True
return o
def join(self, o): #현 text와 인자로 들어온 오브젝트의 text를 현 오브젝트의 text에 +함
if o.tag() != TAG_TEXT:
return False
if (self._ul and not o._ul) or (not self._ul and o._ul):
return False
if not self.dirty and not o.dirty and self.y() == o.y():
self.dirty = False
else:
self.dirty = True
l = len(self._text)
self.set_text( self._text + o.get_text() )
self.dirty = True
return True
def message_length_KT(self):
if self._ul and self._parent._ul_shape == 'rectangle':
return 0
else:
return self.length_KT()
def message_length(self):
if self._ul and self._parent._ul_shape == 'rectangle':
return 0
else:
return self.length()
def length(self):
return len(self._text)
def length_KT(self):
# shchun : in case non euc-kr
#return len(self._text.encode('euc-kr'))
try:
ret = len(self._text.encode('euc-kr'))
except:
ret = len(self._text)
return ret
# end shchun
def cut(self, index, length):
#assert index >= 0
#assert index + length <= self.length()
text = self._text[:index] + self._text[index+length:]
self.set_text(text)
self.dirty = True
class RichTextObject_Image(RichTextObject):
def __init__(self, parent):
RichTextObject.__init__(self, parent)
self.dirty = True
self._widget = runtime.evas.image()
self._ul = None
def tag(self):
return TAG_IMAGE
def move(self, x, y):
self._widget.move(x+2,y)
width,height = self._widget.geometry_get()[2:]
self.geom_cache = (x, y, width + 2*2, height)
def set_text(self, data):
self._widget.file_set(data.encode('utf-8'))
self._widget.smooth_scale_set(0)
width, height = self._widget.size_get()
self._widget.fill_set(0,0,width,height)
self._widget.resize(width,height)
x,y,width,height = self._widget.geometry_get()
self.geom_cache = (x, y, width + 2*2, height)
def get_text(self):
return unicode(self._widget.file_get(), 'utf-8')
def message_length_KT(self):
return self.message_length()
def message_length(self):
p = self.private
if p[0] == 'emoticon':
return len(p[1])
elif p[0] == 'picture':
import utils
return utils.get_file_size(self._widget.file_get())
elif p[0] == 'audio':
import utils
return utils.get_file_size(p[1])
else:
pass
#print 'p1 = [%s]' % p1
#assert False
##########################################################################
class RichTextBase(widget.Widget):
def __init__(self, pos, size, edit=False):
widget.Widget.__init__(self)
self.x = pos[0]
self.y = pos[1]
self.width = size[0]
self.height = size[1]
self.objs = []
self.clip = None
self._edit = edit
self.cursor = None
self.cursor_hidden = False
self._max = -1
self.hiddenset = 0
self._ul_shape = 'line'
if self._edit:
self.cursor = Cursor(self)
self.cursor_idx = 0
self.cursor_offset_in_obj = 0
self.cursor.queue_update()
def free(self):
widget.Widget.free(self)
for o in self.objs:
o.free()
if self.cursor:
self.cursor.free()
def cursor_end_pos(self):
idx = self.cursor_idx
off = self.cursor_offset_in_obj
self.cursor_idx = len(self.objs)
self.cursor_offset_in_obj = 0
max_cursor_x, max_cursor_y,h = self.cursor_pos_height()
self.cursor_idx = idx
self.cursor_offset_in_obj = off
my_cursor_x, my_cursor_y,h = self.cursor_pos_height()
if my_cursor_x == max_cursor_x:
return 1
else:
return 0
#print "[yylee debug] ",max_cursor_x, my_cursor_x
#print "[yylee debug] cursor_idx:%d, cursor_offset_in_obj=%d" % (self.cursor_idx, self.cursor_offset_in_obj)
#return self.cursor_idx
def set_max(self, max):
self._max = max
def length(self):
l = 0
for o in self.objs:
l += o.length()
return l
def check_internal(self):
return
if not self._edit: return
#assert self.cursor_offset_in_obj >= 0
#if self.cursor_offset_in_obj != 0:
# assert self.cursor_idx < len(self.objs)
# assert self.cursor_offset_in_obj < self.objs[self.cursor_idx].length()
#else:
# assert self.cursor_idx <= len(self.objs)
def show(self):
self.hidden = False
self.formatting()
if self.cursor and not self.cursor_hidden: self.cursor.show()
def hide(self):
for o in self.objs:
o.hide()
if self.cursor: self.cursor.hide()
self.hidden = True
def move(self, x, y):
dx = x - self.x
dy = y - self.y
self.x = x
self.y = y
for o in self.objs:
o.move( o.x() + dx, o.y() + dy )
runtime.evas.render()
def get_text(self):
t = unicode('')
try:
for o in self.objs:
t += o.get_text()
except:
pass
#assert isinstance(t, unicode)
return t.encode('utf-8') #유니코드를 utf-8로 변환
def object_factory(self, tag = TAG_TEXT):
if tag == TAG_IMAGE:
return RichTextObject_Image(self)
elif tag == TAG_TEXT:
return RichTextObject_Text(self, hiddenset = self.hiddenset)
elif tag == TAG_NEWLINE:
o = RichTextObject_NewLine(self)
o.set_private_data(uiconfig.richtext_min_line_height)
return o
else:
pass
#print 'Unknown tag name [%s]' % tag
#assert False
def object_parser(self, text):
objs = []
o = None
data = ''
tag_name = ''
for c in text:
if c == '\r':
continue
if c == '\n':
if o:
#assert o.tag() == TAG_TEXT
o.set_text(data)
objs.append(o)
data = ''
o = None
objs.append(self.object_factory(TAG_NEWLINE))
continue
elif c == SI:
if o:
o.set_text(data)
objs.append(o)
data = ''
o = None
tag_name = c
elif c == SO:
tag_name += c
o = self.object_factory(tag_name)
tag_name = ''
else:
if tag_name:
tag_name += c
else:
if not o:
o = self.object_factory()
data += c
if o:
o.set_text(data)
objs.append(o)
o = None
return objs
def handle_join(self, o, o2):
if self._edit:
coff = self.cursor_offset_in_obj
cidx = self.cursor_idx
i2 = self.objs.index(o2)
if i2 == cidx:
cidx -= 1
coff = o.length() - o2.length() + coff
elif cidx > i2:
cidx -= 1
self.cursor_offset_in_obj = coff
self.cursor_idx = cidx
self.objs.remove(o2)
o2.free()
def handle_split(self, o, o2):
i = self.objs.index(o)
self.objs.insert(i+1, o2);
if self._edit:
coff = self.cursor_offset_in_obj
cidx = self.cursor_idx
if i == cidx:
if coff >= o.length():
cidx += 1
coff -= o.length()
elif i < cidx:
cidx += 1
self.cursor_offset_in_obj = coff
self.cursor_idx = cidx
def set_text(self, text):
#assert not isinstance(text, unicode)
try:
text = unicode(text, 'utf-8')
except:
text = ''
for o in self.objs:
o.free()
self.objs = []
self.objs = self.object_parser(text)
if self.objs:
self.formatting()
if self._edit: self.cursor_end()
def insert_objs(self, nobjs):
#print "[yylee debug] _max:%d, length:%d"%(self._max, self.message_length_KT())
#assert self._edit
'''
if self._max > 0:
left = self._max - self.message_length()
tmpobjs = nobjs
nobjs = []
for o in tmpobjs:
if o.message_length() <= left:
left -= o.message_length()
nobjs.append(o)
else:
o.free()
'''
if self._max > 0:
left = self._max - self.message_length_KT()
tmpobjs = nobjs
nobjs = []
for o in tmpobjs:
if o.message_length_KT() <= left:
left -= o.message_length_KT()
nobjs.append(o)
else:
o.free()
idx = self.cursor_idx
off = self.cursor_offset_in_obj
o2 = None
if off > 0:
o2 = self.objs[idx].split_in_length(off)
#assert o2
idx += 1
off = 0
for o in nobjs:
if idx > 0:
last_o = self.objs[idx-1]
o.move(last_o.x()+last_o.width(), last_o.y())
o.dirty = True
self.objs.insert(idx, o) #전체 오브젝트 관리 objs에 삽입
idx += 1
if o2:
self.objs.insert(idx, o2)
#assert off == 0
# just for assertion
#if idx == len(self.objs): assert off == 0
#assert idx <= len(self.objs)
#if idx < len(self.objs): assert off < self.objs[idx].length()
self.cursor_idx = idx
self.cursor_offset_in_obj = off
self.check_internal()
self.formatting()
self.check_internal()
if not self.hidden:
# in showed only. see widget.py
self.cursor.queue_update()
def insert_text(self, text, ul = False):
#assert not isinstance(text, unicode)
self.insert_unicode_text(unicode(text, 'utf-8'))
def set_edit_buf(self, text):
first = True
for o in self.objs:
if o._ul:
if first:
o.set_text(text)
o.update_ul()
first = False
else:
self.objs.remove(o)
self.cursor_idx -= 1
self.formatting()
def insert_unicode_text(self, text, ul=False):
nobjs = self.object_parser(text)
for o in nobjs:
if o.tag() == TAG_TEXT:
o.enable_ul(ul)
self.insert_objs(nobjs)
def can_be_inserted(self, o):
if self._max > 0:
left = self._max - self.message_length()
if o.message_length() > left:
return False
return True
def insert_image(self, filename, data = None):
o = self.object_factory(TAG_IMAGE)
o.set_text(filename)
o.set_private_data(data)
if not self.can_be_inserted(o):
o.free()
raise RichTextOverflowError, ''
self.insert_objs((o,))
def insert_audio(self, filename, data = None):
o = self.object_factory(TAG_IMAGE)
o.set_text(uiconfig.image_dir + uiconfig.edit_audio_icon)
o.set_private_data(('audio', filename, data))
if not self.can_be_inserted(o):
o.free()
raise RichTextOverflowError, ''
self.insert_objs((o,))
def get_data(self):
data = []
for o in self.objs:
data.append(o.get_data())
return data
def get_length(self):
l = 0
for o in self.objs:
l += o.length()
return l
def message_length_KT(self): #지금까지 입력된 char(오브젝트)의 수를 리턴한다.
l = 0
for o in self.objs:
l += o.message_length_KT()
return l
def message_length(self): #지금까지 입력된 char(오브젝트)의 수를 리턴한다.
l = 0
for o in self.objs:
l += o.message_length()
return l
def set_max(self, max):
self._max = max
def set_clip(self, clip):
self.clip = clip
for o in self.objs:
o.set_clip(clip)
def backspace(self, count=1):
#assert self._edit
idx = self.cursor_idx
off = self.cursor_offset_in_obj
for i in range(idx, len(self.objs)):
self.objs[i].dirty = True
while count > 0:
if self.cursor_offset_in_obj == 0:
if idx == 0:
return False
o = self.objs[idx-1]
if o.length() <= count:
count -= o.length()
idx = self.objs.index(o)
off = 0
o.free()
self.objs.remove(o)
# RHC / [20060809_1]
# SMS Write 시에 줄바꿈에 문제가 있다.
try:
self.objs[idx-1].dirty = True
except IndexError:
#roxia_trace('IndexError')
pass
# RHC / [20060809_1]--
else:
o.cut(o.length()-count, count)
idx = self.objs.index(o) + 1
off = 0
count = 0
else:
o = self.objs[idx]
#assert off < o.length()
if off <= count:
count -= off
o.cut(0, off)
idx = self.objs.index(o)
off = 0
else:
off -= count
o.cut(off, count)
idx = self.objs.index(o)
count = 0
self.cursor_idx = idx
self.cursor_offset_in_obj = off
self.check_internal()
self.formatting()
self.check_internal()
self.cursor.queue_update()
def cursor_pos_height(self):
idx = self.cursor_idx
off = self.cursor_offset_in_obj
if off == 0:
if idx == 0:
return self.x, self.y, uiconfig.richtext_min_line_height
else:
#assert idx <= len(self.objs)
if idx >= len(self.objs):
o = self.objs[idx-1]
if o.tag() == TAG_NEWLINE:
return self.x, (o.y() + o.get_private_data()), uiconfig.richtext_min_line_height
else:
return (o.x() + o.width() - 2), o.y(), o.height()
else:
o = self.objs[idx]
return o.x(), o.y(), o.height()
else:
o = self.objs[idx]
return (o.x() + o.width(off) - 2), o.y(), o.height() # 1 is just for tuning
def cursor_backward(self):
#assert self._edit
if self.cursor_offset_in_obj == 0:
if self.cursor_idx == 0:
return False
self.cursor_idx -= 1
self.cursor_offset_in_obj = self.objs[self.cursor_idx].length() - 1
else:
self.cursor_offset_in_obj -= 1
self.formatting()
self.cursor.queue_update()
return True
def cursor_forward(self):
#assert self._edit
if self.cursor_idx == len(self.objs):
return True
isul = False
for o in self.objs:
if o._ul:
isul = True
break
if isul:
noff = self.cursor_offset_in_obj
else:
noff = self.cursor_offset_in_obj + 1
if noff == self.objs[self.cursor_idx].length():
noff = 0
self.cursor_idx += 1
self.cursor_offset_in_obj = noff
self.formatting()
self.cursor.queue_update()
return True
def cursor_up(self):
return False
def cursor_down(self):
return False
def cursor_start(self):
self.cursor_idx = 0
self.cursor_offset_in_obj = 0
self.cursor.queue_update()
def cursor_end(self):
self.cursor_idx = len(self.objs)
self.cursor_offset_in_obj = 0
self.cursor.queue_update()
def cursor_adj_ch(self):
if self.cursor_offset_in_obj == 0:
if self.cursor_idx == 0:
return False
else:
idx = self.cursor_idx-1
off = self.objs[idx].length()-1
else:
idx = self.cursor_idx
off = self.cursor_offset_in_obj - 1
if self.objs[idx].tag() == TAG_TEXT:
t = self.objs[idx].get_text()
return t[off]
return False
def set_ul_shape(self, shape):
#assert shape in ('line', 'rectangle')
self._ul_shape = shape
def is_start_of_sentance(self):
idx = self.cursor_idx
off = self.cursor_offset_in_obj
if off > 0:
o = self.objs[idx]
for j in range(off-1, -1, -1):
c = o.get_text()[j]
if c in (' ', '\t'):
continue
if c in ('.', '?', '!'):
return True
else:
return False
if idx == 0:
return True
for i in range(idx-1, -1, -1):
o = self.objs[i]
if o.tag() != TAG_TEXT:
return True
for j in range(o.length()-1, -1, -1):
c = o.get_text()[j]
if c in (' ', '\t'):
continue
if c in ('.', '?', '!'):
return True
else:
return False
return True
def full(self):
if self._max > 0 and self.message_length_KT() >= self._max:
return True
return False
def cursor_show(self):
self.cursor_hidden = False
if self.cursor: self.cursor.show()
def cursor_hide(self):
self.cursor_hidden = True
if self.cursor: self.cursor.hide()
########################################################################
class RichText(RichTextBase):
def __init__(self, pos=(0,0), size=(200,200), edit=False, text_font=uiconfig.richtext_font, text_color=uiconfig.richtext_color):
RichTextBase.__init__(self, pos, size, edit)
self._format_delayed = False
self._text_font = text_font
self._text_color = text_color
def get_height(self):
y1 = self.y
y2 = y1
if not self.objs:
return 0
last_y = self.objs[-1].y()
for i in range(len(self.objs)-1, -1, -1):
o = self.objs[i]
if o.y() < last_y:
break
if y2 < o.y() + o.height():
y2 = o.y() + o.height()
return y2 - y1
def formatting(self):
if self.hidden:
return
if self._format_delayed:
return
base_x = self.x #edit pos
base_y = self.y
x2 = base_x + self.width
#clipping area
if self.clip:
cx1, cy1, cw, ch = self.clip.geometry_get()
cx2 = cx1 + cw
cy2 = cy1 + ch
else:
cx1 = base_x
cy1 = base_y
cx2 = x2
cy2 = base_x + self.height
#editor에 들어가는 문자 라인수
base_line_height = uiconfig.richtext_min_line_height
ypos = base_y
xpos = base_x
line_height = base_line_height
force = False
# join objs in same line
objs = self.objs[:]
objs.reverse()
while objs: #같은 라인의 text를 하나의 오브젝트로 만듬
o = pop(objs)
if o.tag() != TAG_TEXT:
continue
o2 = pop(objs)
while o2 and o2.y() == o.y() and o.join(o2):
self.handle_join(o, o2)
o2 = pop(objs)
if o2: objs.append(o2)
objs = self.objs[:]
objs.reverse()
# skip un-touched objs
count = 0
while objs:
o = pop(objs)
if o.dirty:
objs.append(o)
break
o.show()
count += 1
if objs:
o = objs[-1]
last_clean_obj_idx = self.objs.index(o)-1
if last_clean_obj_idx >= 0:
o = self.objs[last_clean_obj_idx]
if o.tag() == TAG_NEWLINE:
xpos = base_x
ypos = o.y() + o.get_private_data()
line_height = base_line_height
else:
xpos = o.x() + o.width()
ypos = o.y()
line_height = base_line_height
if o.height() > line_height:
line_height = o.height()
for i in range(last_clean_obj_idx-1, -1, -1):
o = self.objs[i]
if o.y() < ypos:
break;
if o.height() > line_height:
line_height = o.height()
# join
nobjs = []
count = 0
while objs:
o = pop(objs)
o2 = pop(objs)
while o2 and o.join(o2):
count += 1
self.handle_join(o, o2)
o2 = pop(objs)
if o2: objs.append(o2)
nobjs.append(o)
objs = nobjs
objs.reverse()
# start to layout from the first dirty object
last_o = None
while objs:
o = pop(objs)
if o.tag() == TAG_NEWLINE:
o.move(xpos, ypos)
o.show()
o.set_private_data(line_height)
o.dirty = False
ypos += line_height
xpos = base_x
line_height = base_line_height
elif o.tag() == TAG_IMAGE:
if xpos + o.width() <= x2:
o.move(xpos, ypos)
o.show()
o.dirty = False
if line_height < o.height(): line_height = o.height()
xpos += o.width()
else:
# start in new line
objs.append(o)
xpos = x2
elif o.tag() == TAG_TEXT:
if xpos + o.width() <= x2:
o.move(xpos, ypos)
o.show()
o.dirty = False
if line_height < o.height(): line_height = o.height()
xpos += o.width()
else:
if o._ul:
o2 = o.split(base_x, x2-xpos, True)
elif last_o and last_o.tag() == TAG_TEXT and last_o._ul:
o2 = o.split(base_x, x2-xpos, False)
if not o2:
o2 = o.split(base_x, x2-xpos, True)
else:
o2 = o.split(base_x, x2-xpos, False)
if not o2:
if xpos == base_x:
o2 = o.split(base_x, x2-xpos, True)
if o2:
o.move(xpos, ypos)
o.show()
o.dirty = False
if line_height < o.height(): line_height = o.height()
self.handle_split(o, o2)
objs.append(o2)
else:
objs.append(o)
# start in new line
xpos = x2
else:
pass
#print 'Unknown tag [%s]' % o.tag()
#assert False
if xpos == x2:
# 20: formatting margin
# cursor_down을 할때 formatting하기 전에 cursor_down을
# 수행하고 formatting을 하기 때문에 formatting할때 한줄
# 정도의 margin을 주지 않으면 이상한곳으로 cursor가
# 이동하는 경우가 생길 수 있다.
if ypos >= cy2 + 20:
if self._edit:
if self.objs.index(o) > self.cursor_idx:
break;
ypos += line_height
xpos = base_x
line_height = base_line_height
#assert xpos < x2
last_o = o
force = False
# hiding remain objects
while objs: objs.pop().hide()
self.set_clip(self.clip)
def cursor_up(self):
#assert self._edit
if self.cursor_idx == 0 and self.cursor_offset_in_obj == 0:
return False
cur_x, cur_y = self.cursor_pos_height()[:2]
i = self.cursor_idx - 1
# skip objects in the same line
while i >= 0 and self.objs[i].y() >= cur_y:
i -= 1
# find object in cur_x
while i >= 0:
if self.objs[i].x() <= cur_x:
break;
i -= 1
if i < 0:
# not found
self.cursor_idx = 0
self.cursor_offset_in_obj = 0
else:
self.cursor_idx = i
o = self.objs[i]
for off in range(o.length()):
off += 1
if o.x() + o.width(off) >= cur_x:
if off > 0:
if abs(o.x() + o.width(off) - cur_x) > abs(o.x() + o.width(off-1) - cur_x):
off -= 1
break;
#assert off <= o.length()
if off == o.length():
off -= 1
self.cursor_idx = i
self.cursor_offset_in_obj = off
self.formatting()
self.cursor.queue_update()
return True
def cursor_down(self):
#assert self._edit
#assert self.cursor_idx <= len(self.objs)
if self.cursor_idx == len(self.objs):
return False
idx = self.cursor_idx
off = self.cursor_offset_in_obj
cur_x, cur_y = self.cursor_pos_height()[:2]
i = self.cursor_idx
# skip objects in the same line
while i < len(self.objs) and self.objs[i].y() <= cur_y:
i += 1
# find object in cur_x
while i < len(self.objs):
if self.objs[i].x() + self.objs[i].width() > cur_x:
break
if i+1 < len(self.objs):
if self.objs[i+1].y() != self.objs[i].y():
break
i += 1
if i >= len(self.objs):
# not found
self.cursor_idx = len(self.objs)
self.cursor_offset_in_obj = 0
else:
self.cursor_idx = i
o = self.objs[i]
for off in range(o.length()):
off += 1
if o.x() + o.width(off) >= cur_x:
if abs(o.x() + o.width(off) - cur_x) > abs(o.x() + o.width(off-1) - cur_x):
off -= 1
break;
#assert off <= o.length()
if off == o.length():
off -= 1
self.cursor_idx = i
self.cursor_offset_in_obj = off
self.formatting()
self.cursor.queue_update()
return True