/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2000-2014 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine is distributed in the hope that it will * * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package tc.samples.api.ui; import tc.samples.api.*; import totalcross.io.*; import totalcross.sys.*; import totalcross.ui.*; import totalcross.ui.dialog.*; import totalcross.ui.event.*; import totalcross.ui.gfx.*; import totalcross.ui.image.*; public class ImageBookSample extends BaseContainer { GridContainer gc; static boolean isVert; RadioGroupController rg; String[] images = { "tc/samples/api/ui/books/book1.png", "tc/samples/api/ui/books/book2.png", "tc/samples/api/ui/books/book3.png", "tc/samples/api/ui/books/book4.png", "tc/samples/api/ui/books/book5.png", "tc/samples/api/ui/books/book6.png", "tc/samples/api/ui/books/book7.png", "tc/samples/api/ui/books/book8.png", }; // saves the files that contains the images // always store the reference to the file, NEVER the image bytes! can also be the rowid or primary key if the image is inside a database String[] imageNames; private String imageFolder; // parameters that you can tweak // controls the gaps within the Cell private static final int CELL_GAP = 0;// uncomment to change the space - Settings.uiAdjustmentsBasedOnFontHeight ? 20 : 2; private static final int IMAGE_GAP= CELL_GAP*2; // controls the image quality private static final int TOTAL_ITEMS = 1000; private static final int GRID_LINES = 3; private static final int GRID_COLS = 4; private static final int CACHE_PAGES = 10; // big value = more memory consumed private static final int LINES_PER_PAGE = 6; // auto-adjust the font size; if set to 0, the size is unchanged // thread that loads and unloads the images dynamically ImageLoader imgload; class ImageLoader extends Thread { int max; int perpage; int current=-1; String[] arqs; Image[] loaded; int lastIni,lastEnd; IOException ex; public ImageLoader(int max, int perpage, String[] arqs) { this.max = max; this.perpage = perpage; this.arqs = arqs; loaded = new Image[arqs.length]; } public void run() { int lastcur = -1; while (true) { while (lastcur == current) Vm.sleep(10); int range = max/2; lastcur = current; int lastMinIdx = lastcur - range; if (lastMinIdx < 0) lastMinIdx = 0; int lastMaxIdx = lastcur + range; if (lastMaxIdx >= arqs.length) lastMaxIdx = arqs.length-1; if (lastIni != lastEnd) { for (int i = lastIni; i < lastMinIdx; i++) loaded[i] = null; for (int i = lastMaxIdx+1; i <= lastEnd; i++) loaded[i] = null; } lastIni = lastMinIdx; lastEnd = lastMaxIdx; ex = null; Vm.tweak(Vm.TWEAK_DISABLE_GC,true); for (int i = lastMinIdx; i <= lastMaxIdx && lastcur == current; i++) if (loaded[i] == null) loaded[i] = loadImage(i); Vm.tweak(Vm.TWEAK_DISABLE_GC,false); } } private byte[] buf = new byte[1]; private Image loadImage(int i) { Image img = null; try { File f = new File(imageFolder+arqs[i],File.READ_WRITE); int s = f.getSize(); if (buf.length < s) buf = new byte[s]; f.readBytes(buf,0,s); f.close(); img = new Image(buf,s); } catch (IOException ioe) { Vm.debug(ioe.getMessage()); ioe.printStackTrace(); ex = ioe; } catch (Throwable e) { Vm.alert(e.getMessage()+" "+Vm.getStackTrace(e)); e.printStackTrace(); } return img; } private void setCurrent(int idx) { if (loaded[idx] != null && ((idx % perpage) != 0 || idx == current)) return; current = idx; } /** Returns the image in the given size */ public Image getImage(int idx) throws IOException { if (ex != null) throw ex; try { setCurrent(idx); while (loaded[idx] == null) Vm.sleep(10); return loaded[idx]; } catch (Exception e) {e.printStackTrace();} return null; } } // class used to show the Image on screen. class DynImage extends Control { int idx; public DynImage(int idx) { this.idx = idx; } public void onPaint(Graphics g) { Image img = null; try { img = imgload.getImage(idx); if (img != null) { double ratio = Math.min((double)width / img.getWidth(), (double)height / img.getHeight()); double oldH = img.hwScaleH, oldW = img.hwScaleW; img.hwScaleH = img.hwScaleW = ratio; g.drawImage(img,(width - img.getWidth())/2,(height - img.getHeight())/2); img.hwScaleH = oldH; img.hwScaleW = oldW; } } catch (Exception ioe) {} if (img == null) { // no memory, draw a rect with a x g.foreColor = Color.BLACK; g.drawRect(0,0,width,height); g.drawLine(0,0,width,height); g.drawLine(width,0,0,height); } } } // class that represents a Grid's cell class ImgCell extends GridContainer.Cell { int idx; boolean highQuality; Label l1,l2; Control img; public ImgCell(int idx) { this(idx,false); } public ImgCell(int idx, boolean highQuality) { this.idx = idx; this.highQuality = highQuality; setBackColor(Color.WHITE); setBorderStyle(BORDER_SIMPLE); // uncomment to remove border } public void initUI() { setInsets(CELL_GAP,CELL_GAP,CELL_GAP,CELL_GAP); l1 = new Label("book "+(idx+1),CENTER); l1.autoSplit = true; l2 = new Label("Written by J.R.Olling",CENTER); l2.autoSplit = true; add(l1,LEFT,TOP,FILL,PREFERRED); l1.reposition(); add(l2,LEFT,BOTTOM,FILL,PREFERRED); l2.reposition(); try { img = new DynImage(idx); if (highQuality) { Image image = imgload.getImage(idx); double ratio = Math.min((double)width / image.getWidth(), (double)height / image.getHeight()); ImageControl ic = new ImageControl(image.getSmoothScaledInstance((int)(image.getWidth()*ratio),(int)(image.getHeight()*ratio))); img = ic; ic.setEventsEnabled(true); ic.centerImage = true; } add(img,LEFT,AFTER+IMAGE_GAP,FILL,FIT-IMAGE_GAP,l1); } catch (Throwable t) {img = null;} } public void reposition() { super.reposition(); l1.reposition(); l2.reposition(); img.reposition(); } } // class used to show a selected cell in a window class CellBox extends Window { int idx; public CellBox(int idx) { this.idx = idx; titleGap = 0; } public void initUI() { fadeOtherWindows = true; add(new ImgCell(idx,true),LEFT,TOP,FILL,FILL); } protected boolean onClickedOutside(PenEvent event) { unpop(); return true; } } public void initUI() { try { super.initUI(); setTitle("Image Book"); if (Settings.isIOS() || Settings.isWindowsDevice()) // hack for ios: extract the files and write into the folder { File dir = new File("device/books"); if (!dir.exists()) { try {dir.createDir();} catch (Exception e) {} for (int i = 0; i < 8; i++) { byte[] b = Vm.getFile(images[i]); if (b != null) try { new File("device/books/"+Convert.getFileName(images[i]), File.CREATE_EMPTY).writeAndClose(b); } catch (Exception e) {e.printStackTrace();} else Vm.debug(images[i]+" not found in pkg!"); } } } rg = new RadioGroupController(); add(new Label("Orientation: "),LEFT+gap,TOP+gap); add(new Radio("Horizontal",rg),AFTER+gap,SAME); add(new Radio("Vertical",rg),AFTER+gap,SAME); rg.setSelectedIndex(isVert ? 1 : 0); // folder that contains the images. can be "/sdcard", for example imageFolder = Settings.appPath; if (Settings.onJavaSE) imageFolder += "/src/tc/samples/api/ui"; imageFolder += "/books/"; // list images in the folder String[] arqs0 = new File(imageFolder).listFiles(); // IMPORTANT: creates a single array with all image NAMES imageNames = new String[TOTAL_ITEMS]; for (int i = 0; i < imageNames.length; i++) imageNames[i] = arqs0[i % arqs0.length]; // defines orientation // starts the ImageLoader imgload = new ImageLoader(GRID_LINES*GRID_COLS*CACHE_PAGES, GRID_LINES*GRID_COLS, imageNames); imgload.start(); setBackColor(Color.WHITE); addBook(); info = "Click a book for details"; } catch (Exception ee) { MessageBox.showException(ee,true); } } private void addBook() { if (gc != null) remove(gc); // defines the orientation: VERTICAL_ORIENTATION ou HORIZONTAL_ORIENTATION int dir = isVert ? GridContainer.VERTICAL_ORIENTATION : GridContainer.HORIZONTAL_ORIENTATION; add(gc = new GridContainer(dir),LEFT,TOP+fmH+gap*2,FILL,FILL); gc.setBackColor(Color.WHITE); Flick f = gc.getFlick(); f.shortestFlick = 1000; // increases because the image's load time affects the flick f.longestFlick = TOTAL_ITEMS > 500 ? 6000 : 2500; gc.setPageSize(GRID_COLS,GRID_LINES); gc.setRowsPerPage(LINES_PER_PAGE); addCells(); } private void addCells() { ImgCell []cels = new ImgCell[TOTAL_ITEMS]; for (int i = 0; i < cels.length; i++) cels[i] = new ImgCell(i); gc.setCells(cels); } // intercepts the cell pressed event and shows it in a popup screen public void onEvent(Event e) { super.onEvent(e); if (e.type == ControlEvent.PRESSED) { if (e.target instanceof ImgCell) { int idx = ((ImgCell)e.target).idx; CellBox mc = new CellBox(idx); mc.setRect(CENTER,CENTER,SCREENSIZE+80,SCREENSIZE+80); mc.popup(); } else if (e.target instanceof Radio) { isVert = rg.getSelectedIndex() == 1; addBook(); } } } public ImageBookSample() { super.isSingleCall = true; } }