1#!/usr/bin/python 2# -*- coding: utf-8 -*- 3 4 5# 6# 7# UTF-8 test program for the Fast Light Tool Kit (FLTK). 8# 9# Copyright 1998-2009 by Bill Spitzak and others. 10# 11# This library is free software; you can redistribute it and/or 12# modify it under the terms of the GNU Library General Public 13# License as published by the Free Software Foundation; either 14# version 2 of the License, or (at your option) any later version. 15# 16# This library is distributed in the hope that it will be useful, 17# but WITHOUT ANY WARRANTY; without even the implied warranty of 18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19# Library General Public License for more details. 20# 21# You should have received a copy of the GNU Library General Public 22# License along with this library; if not, write to the Free Software 23# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 24# USA. 25# 26# Please report all bugs and problems to "fltk-bugs@fltk.org". 27# 28 29from fltk import * 30import sys, math 31 32# 33# Font chooser widget for the Fast Light Tool Kit(FLTK). 34# 35 36 37DEF_SIZE = 16 # default value for the font size picker 38 39fnt_chooser_win = None 40fontobj = None 41sizeobj = None 42 43fnt_cnt = None 44refresh_btn = None 45choose_btn = None 46fix_prop = None 47own_face = None 48 49sizes = None 50numsizes = None 51pickedsize = DEF_SIZE 52label = "" 53 54main_win = None 55thescroll = None 56extra_font = None 57 58font_count = 0 59first_free = 0 60 61label = None 62 63 64class FontDisplay(Fl_Widget): 65 def __init__(self, B, X, Y, W, H, L): 66 Fl_Widget.__init__(self, X, Y, W, H, L) 67 self.box(B) 68 self.font = 0 69 self.size = DEF_SIZE 70 self.l = L 71 72 def draw(self): 73 global label 74 fl_draw_box(self.box(), self.x(), self.y(), self.w(), self.h(), self.color()) 75 fl_font(self.font, self.size) 76 fl_color(FL_BLACK) 77 fl_draw(label, self.x()+3, self.y()+3, self.w()-6, self.h()-6, self.align()) 78 79 def test_fixed_pitch(self): 80 w1 = 0 81 w2 = 0 82 h1 = 0 83 h2 = 0 84 fl_font(self.font, self.size) 85 86 w1, h1 = fl_measure("MHMHWWMHMHMHM###WWX__--HUW", 0) 87 w2, h2 = fl_measure("iiiiiiiiiiiiiiiiiiiiiiiiii", 0) 88 89 if w1 == w2: 90 return 1 # exact match - fixed pitch 91 92 # Is the font "nearly" fixed pitch? If it is within 5%, say it is... 93 f1 = w1*1.0 94 f2 = w2*1.0 95 delta = math.fabs(f1 - f2) * 5.0 96 if delta <= f1: 97 return 2 # nearly fixed pitch... 98 return 0 # NOT fixed pitch 99 100 101 102textobj = None 103 104 105def size_cb(widget): 106 global textobj 107 108 size_idx = sizeobj.value() 109 110 if size_idx == 0: 111 return 112 113 c = sizeobj.text(size_idx) 114 115 # find the first numeric char 116 i = 0 117 while c[i] < '0' or c[i] > '9': 118 i = i+1 119 # convert the number string to a value 120 pickedsize = int(c[i:]) 121 122 # Now set the font view to the selected size and redraw it. 123 textobj.size = pickedsize 124 textobj.redraw() 125 126 127def font_cb(widget, param): 128 global first_free, numsizes, sizes, sizeobj, textobj, fix_prop 129 130 font_idx = fontobj.value() + first_free 131 if font_idx == 0: 132 return 133 134 font_idx = font_idx-1 135 textobj.font = font_idx 136 sizeobj.clear() 137 138 size_count = numsizes[font_idx-first_free] 139 size_array = sizes[font_idx-first_free] 140 if size_count == 0: 141 # no preferred sizes - probably TT fonts etc... 142 pass 143 elif size_array[0] == 0: 144 # many sizes, probably a scaleable font with preferred sizes 145 j = 1 146 i = 1 147 while i <= 64 or i < size_array[size_count-1]: 148 i = i+1 149 buf = "" 150 if j < size_count and i == size_array[j]: 151 buf = "@b%d"%i 152 j = j+1 153 else: 154 buf = "%d"%i 155 156 sizeobj.add(buf) 157 158 sizeobj.value(pickedsize) 159 else: 160 # some sizes, probably a font with a few fixed sizes available 161 w = 0 162 for i in range(size_count): 163 # find the nearest available size to the current picked size 164 if size_array[i] <= pickedsize: 165 w = i 166 167 buf = "@b%d"%size_array[i] 168 sizeobj.add(buf) 169 sizeobj.value(w+1) 170 # force selection of nearest valid size, then redraw 171 size_cb(sizeobj) 172 173 # Now check to see if the font looks like a fixed pitch font or not... 174 looks_fixed = textobj.test_fixed_pitch() 175 if looks_fixed != 0: 176 if looks_fixed > 1: 177 fix_prop.value("near") 178 else: 179 fix_prop.value("fixed") 180 181 else: 182 fix_prop.value("prop") 183 184 185def choose_cb(widget): 186 global fontobj, first_free, sizeobj, main_win 187 188 font_idx = fontobj.value()+first_free 189 if font_idx == 0: 190 print("No font chosen") 191 else: 192 font_idx = font_idx-1 193 name, font_type = Fl.get_font_name(font_idx) 194 print("idx %d\nUser name :%s:"%( font_idx, name)) 195 print("FLTK name :%s:"%( Fl.get_font(font_idx))) 196 197 Fl.set_font(extra_font, font_idx) 198 199 size_idx = sizeobj.value() 200 if size_idx == 0: 201 print("No size selected") 202 else: 203 c = sizeobj.text(size_idx) 204 205 # find the first numeric char 206 i = 0 207 while c[i] < '0' or c[i] > '9': 208 i = i+1 209 # convert the number string to a value 210 pickedsize = int(c[i:]) 211 212 main_win.redraw() 213 214def refresh_cb(widget): 215 global main_win 216 main_win.redraw() 217 218def own_face_cb(widget): 219 global first_free, fontobj, fnt_chooser_win, own_face, font_count 220 221 cursor_restore = 0 222 i_was = -1 223 224 if i_was < 0: 225 i_was = 1 226 else: 227 # record which was the topmost visible line 228 i_was = fontobj.topline() 229 fontobj.clear() 230 # Populating the font widget can be slower than an old dog with three legs 231 # on a bad day, show a wait cursor 232 fnt_chooser_win.cursor(FL_CURSOR_WAIT) 233 cursor_restore = 1 234 235 # Populate the font list with the names of the fonts found 236 first_free = FL_FREE_FONT 237 238 font_idx = first_free 239 font_type = 0 240 while font_idx < font_count: 241 name, font_type = Fl.get_font_name(font_idx) 242 font_idx = font_idx+1 243 buf = "" 244 245 if own_face.value() == 0: 246 prefix="" 247 if font_type&FL_BOLD: 248 prefix = prefix+"@b" 249 if font_type&FL_ITALIC: 250 prefix = prefix+"@i" 251 buf = prefix+"@."+name 252 else: 253 buf="@F%d@.%s"%(font_idx, name) 254 fontobj.add(buf) 255 256 fontobj.topline(i_was) 257 if cursor_restore != 0: 258 fnt_chooser_win.cursor(FL_CURSOR_DEFAULT) 259 260def create_font_widget(): 261 global fontobj 262 global sizeobj 263 global fnt_cnt 264 global fnt_chooser_win 265 global refresh_btn 266 global stat_bar 267 global textobj, own_face, fix_prop , label 268 269 fnt_chooser_win = Fl_Double_Window(380, 420, "Font Selector") 270 271 label = "Font Sample\n" 272 n = 0; 273 c = ord(' ')+1 274 while c < 127: 275 if not c&0x1f: 276 label = label+'\n' 277 if chr(c)=='@': 278 label = label+chr(c) 279 label = label+chr(c) 280 c = c+1 281 282 label = label+'\n' 283 284 c = 0xA1 285 while c < 0x600: 286 n = n+1 287 if not n&0x1f: 288 label = label+'\n' 289 if sys.version > '3': 290 label = label+str(chr(c).encode("utf-8")) 291 else: 292 label = label+unichr(c).encode("utf-8") 293 #label = label+unichr(c) 294 c = c+9 295 #label = label+'\0' 296 297 textobj = FontDisplay(FL_ENGRAVED_BOX, 10, 10, 360, 90, label) 298 # 299 #textobj = FontDisplay(FL_ENGRAVED_BOX, 10, 10, 360, 90, None) 300 textobj.align(FL_ALIGN_TOP | FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); 301 textobj.color(53, 3); 302 303 fontobj = Fl_Hold_Browser(10, 110, 290, 270) 304 fontobj.box(FL_ENGRAVED_BOX) 305 fontobj.color(53, 3) 306 fontobj.callback(font_cb, 0) 307 fnt_chooser_win.resizable(fontobj) 308 309 sizeobj = Fl_Hold_Browser(310, 110, 60, 270) 310 sizeobj.box(FL_ENGRAVED_BOX) 311 sizeobj.color(53, 3) 312 sizeobj.callback(size_cb) 313 314 # Create the status bar 315 stat_bar = Fl_Group (10, 385, 380, 30) 316 stat_bar.begin() 317 318 fnt_cnt = Fl_Value_Output(10, 390, 40, 20) 319 fnt_cnt.label("fonts") 320 fnt_cnt.align(FL_ALIGN_RIGHT) 321 322 fix_prop = Fl_Output(100, 390, 40, 20) 323 fix_prop.color(FL_BACKGROUND_COLOR) 324 fix_prop.value("prop") 325 fix_prop.clear_visible_focus() 326 327 own_face = Fl_Check_Button(150, 390, 40, 20, "Self") 328 own_face.value(0) 329 own_face.type(FL_TOGGLE_BUTTON) 330 own_face.clear_visible_focus() 331 own_face.callback(own_face_cb) 332 own_face.tooltip("Display font names in their own face") 333 334 dummy = Fl_Box(220, 390, 1, 1) 335 336 choose_btn = Fl_Button(240, 385, 60, 30) 337 choose_btn.label("Select") 338 choose_btn.callback(choose_cb) 339 340 refresh_btn = Fl_Button(310, 385, 60, 30) 341 refresh_btn.label("Refresh") 342 refresh_btn.callback(refresh_cb) 343 344 stat_bar.end() 345 stat_bar.resizable (dummy) 346 347 fnt_chooser_win.end() 348 349 350def make_font_chooser(): 351 global sizes, numsizes, font_count 352 # create the widget frame 353 create_font_widget() 354 355 # Load the systems available fonts - ask for everything 356 if sys.platform == 'win32': 357 font_count = Fl.set_fonts("*") 358 elif sys.platform == 'apple': 359 font_count = Fl.set_fonts("*") 360 else: 361 # Load the systems available fonts - ask for everything that claims to be iso10646 compatible 362 #font_count = Fl.set_fonts("-*-*-*-*-*-*-*-*-*-*-*-*-iso10646-1") 363 font_count = Fl.set_fonts("*") 364 365 # allocate space for the sizes and numsizes array, now we know how many entries it needs 366 sizes = [None]*font_count 367 numsizes = [0]*font_count 368 369 # Populate the font list with the names of the fonts found 370 first_free = FL_FREE_FONT; 371 font_idx = first_free 372 while font_idx < font_count: 373 # Find out how many sizes are supported for each font face 374 size_array = Fl.get_font_sizes(font_idx) 375 size_count = len(size_array) 376 numsizes[font_idx-first_free] = size_count 377 if size_count != 0: # if the font has multiple sizes, populate the 2-D sizes array 378 sizes[font_idx-first_free] = size_array 379 380 font_idx = font_idx+1 381 # end of font list filling loop 382 383 # Call this once to get the font browser loaded up 384 own_face_cb(None) 385 386 fontobj.value(1) 387 # fontobj.textfont(261); # optional hard-coded font for testing - do not use! 388 389 font_cb(fontobj, 0) 390 391 fnt_cnt.value(font_count) 392 393 return font_count 394 395 396 397# Unicode Font display widget 398 399def box_cb(widget): 400 global thescroll 401 if widget.value() == 0: 402 thescroll.box(FL_NO_BOX) 403 else: 404 thescroll.box(FL_DOWN_FRAME) 405 thescroll.redraw() 406 407 408class right_left_input(Fl_Input): 409 def __init__(self, x, y, w, h): 410 Fl_Input.__init__(self,x,y,w,h) 411 412 def draw(self): 413 pass 414 if self.type() == FL_HIDDEN_INPUT: 415 return 416 b = self.box() 417 if self.damage() & FL_DAMAGE_ALL: 418 fl_draw_box(self.box(), self.x(), self.y(), self.w(), self.h(), self.color()) 419 self.drawtext(self.x()+Fl.box_dx(b)+3, self.y()+Fl.box_dy(b), self.w()-Fl.box_dw(b)-6, self.h()-Fl.box_dh(b)) 420 421 def drawtext(self, X, Y, W, H): 422 fl_color(self.textcolor()) 423 fl_font(self.textfont(), self.textsize()) 424 fl_rtl_draw(self.value(), len(self.value()), X+W, Y+fl_height()-fl_descent()) 425 426 427def i7_cb(i7, i8): 428 i = 0 429 nb = "01234567" 430 buf = "" 431 432 ptr = i7.value() 433 434 for i in range(len(ptr)): 435 if ptr[i] < ' ' or ord(ptr[i]) > 126: 436 buf.append('\\') 437 buf.append("some unicode stuff here") 438 else: 439 if ptr[i] == '\\': 440 buf.append('\\') 441 buf.append(ptr[i]) 442 443 buf.append(chr(0)); 444 i8.value(buf) 445 446 447class UCharDropBox(Fl_Output): 448 def __init__(self, x, y, w, h, label): 449 Fl_Output.__init__(self,x,y,w,h,label) 450 451 def handle(self, event): 452 if event == FL_DND_ENTER or event == FL_DND_DRAG or event == FL_DND_RELEASE: 453 return 1 454 elif event == FL_PASTE: 455 t = Fl.event_text() 456 n = fl_utf8decode(t, t) 457 if n == 0: 458 self.value("") 459 return 1 460 buffer = "" 461 for i in range(n): 462 buffer.append(t[i]) 463 buffer.append(' ') 464 lut = "0123456789abcdef" 465 for i in range(n): 466 buffer.append('\\x') 467 buffer.append(' some lut stuff here') 468 buffer.append(chr(0)) 469 self.value(buffer) 470 return 1 471 return Fl_Output.handle(self, event) 472 473 474if __name__ == '__main__': 475 # If this file is saved as a UTF-8, the latin1 text in the comment 476 # below doesn't look right any more! 477 # Store the specific latin-1 byte values here... this should be equivalent to: 478 latin1 = "\x41\x42\x43\x61\x62\x63\xe0\xe8\xe9\xef\xe2\xee\xf6\xfc\xe3\x31\x32\x33"; 479 utf8 = "" 480 #l = fl_utf8froma(utf8, len(latin1)*5+1, latin1, len(latin1)) 481 482 font_count = make_font_chooser() 483 extra_font = FL_TIMES_BOLD_ITALIC 484 # setup the extra font 485 if sys.platform == 'win32': 486 Fl.set_font(extra_font, " Arial Unicode MS") 487 elif sys.platform == 'darwin': 488 Fl.set_font(extra_font, "Monaco") 489 else: 490 Fl.set_font(extra_font, "-*-*-*-*-*-*-*-*-*-*-*-*-iso10646-1") 491 492 main_win = Fl_Double_Window (200 + 5*75, 400, "Unicode Display Test") 493 main_win.begin() 494 495 i1 = Fl_Input(5, 5, 190, 25) 496 #utf8 = utf8+'\0' 497 utf8 = latin1 498 i1.value(utf8) 499 scroll = Fl_Scroll(200,0,5 * 75,400) 500 off = 2 501 if len(sys.argv) > 1: 502 off = off/16 503 504 y = off 505 506 while y < 0x10000/16: 507 o = 0 508 i = 16*y 509 buf = "" 510 for x in range(16): 511 if sys.version > '3': 512 buf = buf+chr(i) 513 else: 514 buf = buf+unichr(i) 515 o = o+1 516 i = i+1 517 buf = buf+'\0' 518 bu = "0x%04lX"%(y * 16) 519 b = Fl_Input(200,(y-off)*25,60,25) 520 b.value(bu) 521 b = Fl_Input(260,(y-off)*25,400,25) 522 b.textfont(extra_font) 523 if sys.version >= '3': 524 if y >= 0xd80 and y <= 0xdff: 525 # surrogate pairs not allowed 526 buf = "................"+'\0' 527 b.value(buf) 528 else: 529 b.value(buf.encode("utf-8")) 530 #b.value(buf) 531 y = y+1 532 533 main_win.resizable(scroll) 534 scroll.end() 535 536 thescroll = scroll 537 538 i2 = Fl_Input(5, 35, 190, 25) 539 utf8l = utf8.lower() 540 i2.value(utf8l); 541 542 543 i3 = Fl_Input(5, 65, 190, 25) 544 utf8u = utf8l.upper() 545 i3.value(utf8u) 546 547 ltr_txt = "\\->e\xCC\x82=\xC3\xAA"; 548 i4 = Fl_Input(5, 90, 190, 25) 549 i4.value(ltr_txt) 550 i4.textfont(extra_font) 551 552 r_to_l_txt =[ 1610, 1608, 1606, 1604, 1603, 1608, 1583, 0] 553 554 r_l_buf = "" 555 for i in r_to_l_txt: 556 if sys.version >= '3': 557 r_l_buf = r_l_buf+str(chr(i).encode("utf-8")) 558 else: 559 r_l_buf = r_l_buf+unichr(i).encode('utf-8') 560 abuf = r_l_buf 561 i5 = right_left_input(5, 115, 190, 50) 562 i5.textfont(extra_font) 563 i5.textsize(30) 564 i5.value(abuf) 565 566 i7 = Fl_Input(5, 230, 190, 25) 567 i8 = Fl_Input(5, 260, 190, 25) 568 i7.callback(i7_cb, i8) 569 i7.textsize(20) 570 i7.value(abuf) 571 i7.when(FL_WHEN_CHANGED) 572 573 r_to_l_txt1 = [1610, 0x20, 1608, 0x20, 1606, 0x20, 1604, 0x20, 1603, 0x20, 1608, 0x20, 1583, 0] 574 575 r_l_buf = "" 576 for i in r_to_l_txt1: 577 if sys.version >= '3': 578 r_l_buf = r_l_buf+str(chr(i).encode("utf-8")) 579 else: 580 r_l_buf = r_l_buf+unichr(i).encode('utf-8') 581 abuf1 = r_l_buf 582 i6 = right_left_input(5, 175, 190, 50) 583 i6.textfont(extra_font) 584 i6.textsize(30) 585 i6.value(abuf1) 586 587 # Now try Greg Ercolano's Japanese test sequence 588 # SOME JAPANESE UTF8 TEXT 589 # utfstr = "日本語というのは、とても難しい言語です。" 590 utfstr = "\xe4\xbd\x95\xe3\x82\x82\xe8\xa1\x8c\xe3\x82\x8b\xe3\x80\x82"; 591 db = UCharDropBox(5, 300, 190, 30, "") 592 db.textsize(16) 593 db.value("unichar drop box") 594 595 o9 = Fl_Output(5, 330, 190, 45) 596 o9.textfont(extra_font) 597 o9.textsize(30) 598 o9.value(utfstr) 599 600 main_win.end() 601 fl_set_status(0, 370, 100, 30) 602 603 604 main_win.show(sys.argv) 605 606 fnt_chooser_win.show() 607 608 Fl.run() 609 610