[dasher: 11/43] CDasherScreen renders/sizes Labels created by MakeLabel not arbitrary strings
- From: Patrick Welche <pwelche src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dasher: 11/43] CDasherScreen renders/sizes Labels created by MakeLabel not arbitrary strings
- Date: Thu, 23 Jun 2011 18:56:41 +0000 (UTC)
commit 7f92a884312c35522f4ae8a64fd0f52e7a6157b8
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date: Wed May 11 11:30:57 2011 +0100
CDasherScreen renders/sizes Labels created by MakeLabel not arbitrary strings
Delete label to release layout etc. - better fit w/ modern typesetting libraries
Add various MakeLabels+ChangeScreen functions; CDasherScreen resizable via
ScreenResized without full call to ChangeScreen. Initialization: ChangeScreen
before or after Realize. AlphabetManager, ControlManager cache+reuse Labels
internally => preload cache + flush on alphabet change.
AlphabetManager creates own structure of groups+chars with Labels at setup time,
eliding single-child groups once only rather than in every IterateChildGroups
Each platform's Screen's own caching of text size/layout info removed
Mac/iPhone: combine most common implementation into Shared/OpenGLScreen.{h,mm}
in C++; rm old objective-C protocols and Mac DasherViewAqua + ZippyString*.
Both return font size as CGSize, Mac by calling NSSizeToCGSize, which should be
"toll-free bridged" i.e. zero-cost.
MacOSX: make cachedFontName a property
Gtk2: Rm PangoCache; store map<size,PangoLayout> in each PangoLabel; keep a
PangoFontDescription for each font size.
Rm CanvasExperimental, unused so not worth maintaining (?). With Cairo,
with or without modern h/w-accelerated graphics, is there really any point?
Win32: inc adding version of UTF8string_to_wstring that returns result
Src/Common/OpenGLScreen.h | 70 ++
Src/Common/OpenGLScreen.mm | 292 ++++++++
Src/DasherCore/Alphabet/AlphInfo.h | 2 +-
Src/DasherCore/AlphabetManager.cpp | 157 +++--
Src/DasherCore/AlphabetManager.h | 55 +-
Src/DasherCore/ControlManager.cpp | 26 +-
Src/DasherCore/ControlManager.h | 13 +-
Src/DasherCore/ConversionHelper.cpp | 10 +-
Src/DasherCore/ConversionHelper.h | 9 +-
Src/DasherCore/ConversionManager.cpp | 25 +-
Src/DasherCore/ConversionManager.h | 15 +-
Src/DasherCore/ConvertingAlphMgr.cpp | 10 +-
Src/DasherCore/ConvertingAlphMgr.h | 4 +-
Src/DasherCore/DasherInterfaceBase.cpp | 43 +-
Src/DasherCore/DasherInterfaceBase.h | 19 +-
Src/DasherCore/DasherNode.cpp | 4 +-
Src/DasherCore/DasherNode.h | 18 +-
Src/DasherCore/DasherScreen.h | 101 +++-
Src/DasherCore/DasherView.h | 12 +-
Src/DasherCore/DasherViewSquare.cpp | 41 +-
Src/DasherCore/DasherViewSquare.h | 17 +-
Src/DasherCore/MandarinAlphMgr.cpp | 64 ++-
Src/DasherCore/MandarinAlphMgr.h | 21 +-
Src/DasherCore/NodeCreationManager.cpp | 10 +-
Src/DasherCore/NodeCreationManager.h | 7 +
Src/DasherCore/Parameters.h | 3 +-
Src/Gtk2/Canvas.cpp | 137 +++--
Src/Gtk2/Canvas.h | 67 +--
Src/Gtk2/CanvasExperimental.cpp | 914 --------------------------
Src/Gtk2/CanvasExperimental.h | 265 --------
Src/Gtk2/DasherControl.cpp | 81 +--
Src/Gtk2/DasherControl.h | 7 -
Src/Gtk2/Makefile.am | 2 -
Src/Gtk2/PangoCache.cpp | 63 --
Src/Gtk2/PangoCache.h | 26 -
Src/MacOSX/AlphabetLetter.h | 22 -
Src/MacOSX/AlphabetLetter.mm | 112 ----
Src/MacOSX/COSXDasherScreen.h | 157 -----
Src/MacOSX/COSXDasherScreen.mm | 82 ---
Src/MacOSX/Dasher.xcodeproj/project.pbxproj | 75 +--
Src/MacOSX/DasherApp.h | 12 +-
Src/MacOSX/DasherApp.mm | 40 +-
Src/MacOSX/DasherViewAqua.h | 85 ---
Src/MacOSX/DasherViewAqua.mm | 461 -------------
Src/MacOSX/DasherViewCocoa.h | 35 -
Src/MacOSX/DasherViewOpenGL.h | 57 +--
Src/MacOSX/DasherViewOpenGL.mm | 407 +++---------
Src/MacOSX/ZippyCache.h | 31 -
Src/MacOSX/ZippyCache.m | 89 ---
Src/MacOSX/ZippyString.h | 35 -
Src/MacOSX/ZippyString.m | 70 --
Src/MacOSX/ZippyStringGlyph.h | 30 -
Src/MacOSX/ZippyStringGlyph.m | 110 ---
Src/MacOSX/ZippyStringImage.h | 21 -
Src/MacOSX/ZippyStringImage.m | 60 --
Src/Win32/Common/WinUTF8.cpp | 6 +
Src/Win32/Common/WinUTF8.h | 1 +
Src/Win32/Widgets/Canvas.cpp | 10 +-
Src/Win32/Widgets/Screen.cpp | 115 ++--
Src/Win32/Widgets/Screen.h | 42 +-
Src/Win32/Widgets/Screen.inl | 15 +-
Src/iPhone/Classes/AlphabetLetter.h | 20 -
Src/iPhone/Classes/AlphabetLetter.mm | 118 ----
Src/iPhone/Classes/CDasherInterfaceBridge.h | 2 +-
Src/iPhone/Classes/CDasherInterfaceBridge.mm | 8 +-
Src/iPhone/Classes/CDasherScreenBridge.h | 113 ----
Src/iPhone/Classes/CDasherScreenBridge.mm | 85 ---
Src/iPhone/Classes/DasherAppDelegate.h | 1 -
Src/iPhone/Classes/DasherAppDelegate.mm | 24 +-
Src/iPhone/Classes/DasherScreenCallbacks.h | 29 -
Src/iPhone/Classes/EAGLView.h | 42 +-
Src/iPhone/Classes/EAGLView.mm | 324 +++-------
Src/iPhone/Classes/IPhoneFilters.mm | 2 +-
Src/iPhone/Classes/IPhoneInputs.mm | 1 +
Src/iPhone/Dasher.xcodeproj/project.pbxproj | 27 +-
75 files changed, 1372 insertions(+), 4214 deletions(-)
---
diff --git a/Src/Common/OpenGLScreen.h b/Src/Common/OpenGLScreen.h
new file mode 100755
index 0000000..895da5d
--- /dev/null
+++ b/Src/Common/OpenGLScreen.h
@@ -0,0 +1,70 @@
+//
+// AlphabetLetter.h
+// Dasher
+//
+// Created by Alan Lawrence on 20/03/2009.
+// Copyright 2009 Cavendish Laboratory. All rights reserved.
+//
+#ifdef TARGET_OS_IPHONE
+#import <OpenGLES/ES1/gl.h>
+#else
+#import <AppKit/AppKit.h>
+#import <OpenGL/gl.h>
+#endif
+
+#import "DasherScreen.h"
+#include <string>
+
+namespace Dasher {
+ class OpenGLScreen : public CLabelListScreen {
+ protected:
+ class AlphabetLetter : public Label {
+ public: //to OpenGLScreen and subclasses - all read by DrawString
+ NSString *str;
+ GLuint texture;
+ GLfloat texcoords[8];
+ AlphabetLetter(OpenGLScreen *pScreen, const std::string &strText);
+ ~AlphabetLetter();
+ void PrepareTexture();
+ };
+ public:
+ OpenGLScreen(screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y, GLuint *textures);
+ ~OpenGLScreen();
+
+ ///Note, subclasses should override to additionally have buffers ready, etc.
+ void Display();
+ void SetColourScheme(const CColourIO::ColourInfo *pColourScheme);
+ void Polyline(point *Points, int iNum, int iWidth, int iColour);
+ void Polygon(point *points, int iNum, int iFillColour, int iOutlineColour, int iWidth);
+ void DrawRectangle(int x1, int y1, int x2, int y2, int iFillColorIndex, int iOutlineColour, int iThickness);
+ void DrawCircle(screenint iCX, screenint iCY, screenint iR, int iFillColour, int iLineColour, int iLineWidth);
+
+ bool MultiSizeFonts() {return true;}
+ AlphabetLetter *MakeLabel(const std::string &strText);
+ std::pair<screenint,screenint> TextSize(CDasherScreen::Label *label, unsigned int iFontSize);
+ void DrawString(CDasherScreen::Label *label, screenint x, screenint y, unsigned int iFontSize, int iColour);
+ //leave virtual: SendMarker, Display
+ protected:
+ void resize(screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y);
+ void RegenerateLabels();
+ virtual void RenderStringOntoCGContext(NSString *string, CGContextRef context)=0;
+ virtual CGSize TextSize(NSString *str, unsigned int iFontSize)=0;
+ private:
+ typedef struct {
+ float r, g, b;
+ } colour_t;
+
+ //colours in use, we cache these as floats for feeding to OpenGL.
+ colour_t *colourTable;
+
+ ///Caches for circleCallbackWithCentrePoint:... (see therein)
+ float circ_rad;
+ GLshort *circ_coords;
+ int circPoints;
+
+ GLshort rectcoords[8];
+ GLfloat texcoords[8];
+ GLuint *textures;
+
+ };
+}
\ No newline at end of file
diff --git a/Src/Common/OpenGLScreen.mm b/Src/Common/OpenGLScreen.mm
new file mode 100644
index 0000000..ad6935a
--- /dev/null
+++ b/Src/Common/OpenGLScreen.mm
@@ -0,0 +1,292 @@
+//
+// OpenGLScreen.cpp
+// Dasher
+//
+// Created by Alan Lawrence on 20/03/2009.
+// Copyright 2009 Cavendish Laboratory. All rights reserved.
+//
+
+#import "OpenGLScreen.h"
+#import <iostream>
+#import "DasherUtil.h"
+
+using namespace Dasher;
+using namespace std;
+
+OpenGLScreen::OpenGLScreen(screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y, GLuint *_textures)
+: CLabelListScreen(iWidth,iHeight), colourTable(NULL), circ_rad(-1.0f), circ_coords(NULL), circPoints(0), textures(_textures) {
+ resize(iWidth,iHeight,backingWidth,backingHeight,tc_x,tc_y);
+}
+
+void OpenGLScreen::resize(screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y) {
+ CLabelListScreen::resize(iWidth, iHeight);
+ rectcoords[0] = rectcoords[1] = 0;
+ rectcoords[2] = backingWidth; rectcoords[3] = 0;
+ rectcoords[4] = 0; rectcoords[5] = backingHeight;
+ rectcoords[6] = backingWidth; rectcoords[7] = backingHeight;
+
+ texcoords[0] = 0.0; texcoords[1] = tc_y;
+ texcoords[2] = tc_x; texcoords[3] = tc_y;
+ texcoords[4] = 0.0; texcoords[5] = 0.0;
+ texcoords[6] = tc_x; texcoords[7] = 0.0;
+}
+
+OpenGLScreen::~OpenGLScreen() {
+ delete colourTable;
+ delete circ_coords;
+}
+
+void OpenGLScreen::Display() {
+ SendMarker(-1);
+
+ glEnable(GL_TEXTURE_2D);
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_SHORT, 0, rectcoords);
+ glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+ for (int i=0; i<2; i++)
+ {
+ glBindTexture(GL_TEXTURE_2D, textures[i]);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glFlush();
+}
+
+void OpenGLScreen::SetColourScheme(const CColourIO::ColourInfo *pColourScheme) {
+ delete colourTable;
+
+ int iNumColours = pColourScheme->Reds.size();
+
+ colourTable = new colour_t[iNumColours];
+
+ for(int i = 0; i < iNumColours; i++) {
+ colour_t &ct(colourTable[i]);
+ ct.r = pColourScheme->Reds[i] / 255.0;
+ ct.g = pColourScheme->Greens[i] / 255.0;
+ ct.b = pColourScheme->Blues[i] / 255.0;
+ }
+}
+
+void OpenGLScreen::Polyline(point *Points, int iNum, int iWidth, int iColour) {
+ if (iNum < 2) return;
+ GLshort *coords = new GLshort[iNum*2];
+ for (int i = 0; i<iNum; i++)
+ {
+ coords[2*i] = Points[i].x;
+ coords[2*i+1] = Points[i].y;
+ }
+ glDisable(GL_TEXTURE_2D);
+ glColor4f(colourTable[iColour].r, colourTable[iColour].g, colourTable[iColour].b, 1.0);
+ glLineWidth(iWidth);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2, GL_SHORT, 0, coords);
+ glDrawArrays(GL_LINE_STRIP, 0, iNum);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ delete coords;
+}
+
+void OpenGLScreen::Polygon(point *points, int iNum, int iFillColour, int iOutlineColour, int iWidth) {
+ if (iNum < 2) return;
+ GLshort *coords = new GLshort[iNum*2];
+ for (int i = 0; i<iNum; i++)
+ {
+ coords[2*i] = points[i].x;
+ coords[2*i+1] = points[i].y;
+ }
+ glDisable(GL_TEXTURE_2D);
+ if (iFillColour != -1) {
+ glColor4f(colourTable[iFillColour].r, colourTable[iFillColour].g, colourTable[iFillColour].b, 1.0);
+ glVertexPointer(2, GL_SHORT, 0, coords);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, iNum);
+ }
+ if (iWidth>0) {
+ glColor4f(colourTable[iOutlineColour].r, colourTable[iOutlineColour].g, colourTable[iOutlineColour].b, 1.0);
+ glLineWidth(iWidth);
+ glVertexPointer(2, GL_SHORT, 0, coords);
+ glDrawArrays(GL_LINE_LOOP, 0, iNum);
+ }
+ delete coords;
+}
+
+void OpenGLScreen::DrawRectangle(int x1, int y1, int x2, int y2, int iFillColorIndex, int iOutlineColour, int iThickness) {
+ glDisable(GL_TEXTURE_2D);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ if (iFillColorIndex != -1) {
+ glColor4f(colourTable[iFillColorIndex].r, colourTable[iFillColorIndex].g, colourTable[iFillColorIndex].b, 1.0);
+ GLshort coords[8] = {x1,y1, x2,y1, x1,y2, x2,y2};
+ glVertexPointer(2, GL_SHORT, 0, coords);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+ if (iThickness>0) {
+ int oci = iOutlineColour == -1 ? 3 : iOutlineColour;
+ glColor4f(colourTable[oci].r, colourTable[oci].g, colourTable[oci].b, 1.0);
+ glLineWidth(iThickness);
+ GLshort coords[] = {x1,y1, x2,y1, x2,y2, x1,y2};
+ glVertexPointer(2, GL_SHORT, 0, coords);
+ glDrawArrays(GL_LINE_LOOP, 0, 4);
+ }
+}
+
+void OpenGLScreen::DrawCircle(screenint iCX, screenint iCY, screenint iR, int iFillColour, int iOutlineColour, int iLineWidth) {
+ //it's a bit of a hack, but we cache the last-computed set of points round the circle,
+ // as these are the same for all calls with the same radius - and (the hack!) it happens
+ // that the radius tends to be the same every time (as the only call to CDasherScreen::DrawCircle
+ // is from CircleStartHandler!)...
+ if (circ_rad != iR) {
+ delete circ_coords;
+ double costh=1.0f - 1.0f/(2.0f*iR);
+ double th = acos(costh);
+ int numPoints = circPoints = ceil(M_PI/th/2.0f); //for a quarter-circle
+ double sinth = sin(th),x(iR),y(0.0);
+ circ_coords = new GLshort[numPoints*8]; circ_rad = iR;
+ circ_coords[0] = x; circ_coords[1] = y;
+ for (int i=1; i<numPoints; i++) {
+ double nx = x*costh - y*sinth;
+ double ny = x*sinth + y*costh;
+ circ_coords[2*i] = nx;
+ circ_coords[2*i+1] = ny;
+ x=nx; y=ny;
+ }
+ for (int i=0; i<numPoints; i++) {
+ circ_coords[2*(i+numPoints)] = -circ_coords[2*i+1];
+ circ_coords[2*(i+numPoints)+1] = circ_coords[2*i];
+
+ circ_coords[2*(i+numPoints*2)] = -circ_coords[2*i];
+ circ_coords[2*(i+numPoints*2)+1] = -circ_coords[2*i+1];
+
+ circ_coords[2*(i+numPoints*3)] = circ_coords[2*i+1];
+ circ_coords[2*(i+numPoints*3)+1] = -circ_coords[2*i];
+ }
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glTranslatef(iCX, iCY, 0.0);
+ if (iFillColour!=-1) {
+ glColor4f(colourTable[iFillColour].r, colourTable[iFillColour].g, colourTable[iFillColour].b, 1.0);
+ glVertexPointer(2, GL_SHORT, 0, circ_coords);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, circPoints*4);
+ }
+ if (iLineWidth>0) {
+ int oci = iOutlineColour == -1 ? 3 : iOutlineColour;
+ glColor4f(colourTable[oci].r, colourTable[oci].g, colourTable[oci].b, 1.0);
+ glLineWidth(iLineWidth);
+ glVertexPointer(2, GL_SHORT, 0, circ_coords);
+ glDrawArrays(GL_LINE_LOOP, 0, circPoints*4);
+ }
+ glTranslatef(-iCX, -iCY, 0.0);
+}
+
+
+#pragma mark text/label classes+routines
+
+void dump(char *data, int width, int height)
+{
+ static char buf[10240]; buf[0] = 0;
+ for (int h = 0; h < height; h++)
+ {
+ for (int w = 0; w < width; w++)
+ sprintf(buf+strlen(buf), "%i ", *((int*)&data[4* (w + h * width)]));
+ sprintf(buf + strlen(buf), "\n");
+ }
+ std::cout << buf;
+}
+
+OpenGLScreen::AlphabetLetter::AlphabetLetter(OpenGLScreen *pScreen, const string &strText) : Label(pScreen,strText), str(NSStringFromStdString(strText)) {
+ [str retain];
+
+ glGenTextures(1, &texture);
+
+ PrepareTexture();
+}
+
+void OpenGLScreen::AlphabetLetter::PrepareTexture() {
+ int width=1, height=1;
+ GLfloat texw,texh;
+ {
+ CGSize sz = static_cast<OpenGLScreen *>(m_pScreen)->TextSize(str,36);
+ while (width<sz.width) width<<=1;
+ while (height<sz.height) height<<=1;
+ texw = sz.width/(float)width;
+ texh = sz.height/(float)height;
+ }
+
+ char *data = new char[width*height*4];
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CGContextRef context = CGBitmapContextCreate(data, width, height, 8, width*4, colorSpace, kCGImageAlphaPremultipliedLast);
+ CGContextClearRect(context, CGRectMake(0.0, 0.0, width, height));
+
+ static_cast<OpenGLScreen *>(m_pScreen)->RenderStringOntoCGContext(str,context);
+
+ glBindTexture(GL_TEXTURE_2D, texture);
+ //...but tell the GL _not_ to interpolate between texels, as that results in a _big_
+ // grey border round each letter (?!)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+// glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, CGBitmapContextGetData(context));
+
+ CGColorSpaceRelease(colorSpace);
+ CGContextRelease(context);
+ free(data);
+
+ //set texture coords for the corners of the part of the texture we actually
+ // drew into (as the texture had to be sized to a power of 2; note we rendered
+ // into the *bottom* left portion)
+ texcoords[0] = 0.0; texcoords[1] = 1.0;
+ texcoords[2] = texw; texcoords[3] = 1.0;
+ texcoords[4] = 0.0; texcoords[5] = 1.0-texh;
+ texcoords[6] = texw; texcoords[7] = 1.0-texh;
+}
+
+OpenGLScreen::AlphabetLetter::~AlphabetLetter() {
+ [str release];
+ glDeleteTextures(1, &texture);
+}
+
+OpenGLScreen::AlphabetLetter *OpenGLScreen::MakeLabel(const std::string &strText) {
+ return new AlphabetLetter(this,strText);
+}
+
+void OpenGLScreen::RegenerateLabels() {
+ for (set<Label *>::iterator it=LabelsBegin(); it!=LabelsEnd(); it++)
+ static_cast<AlphabetLetter *>(*it)->PrepareTexture();
+}
+
+void OpenGLScreen::DrawString(CDasherScreen::Label *label, screenint x, screenint y, unsigned int iFontSize, int iColour) {
+ //(void)drawWithSize:(int)iSize x:(int)x y:(int)y r:(float)r g:(float)g b:(float)b {
+ const AlphabetLetter *l(static_cast<AlphabetLetter *> (label));
+ // bind and draw
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, l->texture);
+ //"modulate" means to multiply the texture (i.e. 100%=white text, 0%=transparent background)
+ // by the currently selected GL foreground colour
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glColor4f(colourTable[iColour].r, colourTable[iColour].g, colourTable[iColour].b, 1.0); //so we select the colour we want the text to appear in
+ CGSize sz = TextSize(l->str, iFontSize);
+ GLshort coords[8];
+ coords[0] = x; coords[1]=y;
+ coords[2] = x+sz.width; coords[3] = y;
+ coords[4] = x; coords[5] = y+sz.height;
+ coords[6] = x+sz.width; coords[7]=y+sz.height;
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_SHORT, 0, coords);
+ glTexCoordPointer(2, GL_FLOAT, 0, l->texcoords);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+}
+
+pair<screenint,screenint> OpenGLScreen::TextSize(CDasherScreen::Label *label, unsigned int iFontSize) {
+ const AlphabetLetter *l(static_cast<AlphabetLetter *> (label));
+ CGSize sz = TextSize(l->str, iFontSize);
+ //apply "ceil" to floating-point width/height ?
+ return pair<screenint,screenint>(sz.width, sz.height);
+}
+
diff --git a/Src/DasherCore/Alphabet/AlphInfo.h b/Src/DasherCore/Alphabet/AlphInfo.h
index 03abd44..7e137af 100644
--- a/Src/DasherCore/Alphabet/AlphInfo.h
+++ b/Src/DasherCore/Alphabet/AlphInfo.h
@@ -69,7 +69,7 @@ public:
/// Return number of text symbols - inc space and para, but no control/conversion start/end
/// Note symbol numbers are 1-indexed; 0 is reserved to indicate an "unknown symbol" (-1 = End-Of-Stream),
/// and for element 0 of the probability array to contain a 0.
- int GetNumberTextSymbols() const {return m_vCharacters.size();}
+ unsigned int GetNumberTextSymbols() const {return m_vCharacters.size();}
Opts::ScreenOrientations GetOrientation() const {return Orientation;}
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index 7654ec4..4992cc5 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -51,9 +51,9 @@ static char THIS_FILE[] = __FILE__;
#endif
CAlphabetManager::CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, const CAlphabetMap *pAlphabetMap)
- : m_pNCManager(pNCManager), m_pAlphabet(pAlphabet), m_pAlphabetMap(pAlphabetMap), m_pInterface(pInterface) {
+ : m_pFirstGroup(NULL), m_pNCManager(pNCManager), m_pAlphabet(pAlphabet), m_pAlphabetMap(pAlphabetMap), m_pInterface(pInterface) {
//Look for a (single-octet) character not in the alphabet...
- for (char c=33; c<0x80; c++) {
+ for (char c=33; (c&0x80)==0; c++) {
string s(&c,1);
if (pAlphabetMap->Get(s)==0) {
m_sDelim = s;
@@ -62,6 +62,8 @@ CAlphabetManager::CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreati
}
//else, if all single-octet chars are in alphabet - leave m_sDelim==""
// (and we'll find a delimiter for each context)
+
+ m_vLabels.resize(m_pAlphabet->GetNumberTextSymbols()+1);
}
void CAlphabetManager::CreateLanguageModel(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore) {
@@ -89,6 +91,64 @@ CTrainer *CAlphabetManager::GetTrainer() {
return new CTrainer(m_pLanguageModel, m_pAlphabet, m_pAlphabetMap);
}
+void CAlphabetManager::MakeLabels(CDasherScreen *pScreen) {
+ delete m_pFirstGroup;
+ for (vector<CDasherScreen::Label *>::iterator it=m_vLabels.begin(); it!=m_vLabels.end(); it++) {
+ delete (*it); *it = NULL;
+ }
+ m_pFirstGroup = copyGroups(pScreen, 1, m_pAlphabet->GetNumberTextSymbols()+1,m_pAlphabet->m_pBaseGroup);
+}
+
+CAlphabetManager::SGroupInfo::SGroupInfo(CDasherScreen *pScreen, const std::string &strEnc, int iBkgCol, const ::SGroupInfo *pCopy)
+: pChild(NULL), pNext(NULL), strLabel(strEnc + pCopy->strLabel), iStart(pCopy->iStart), iEnd(pCopy->iEnd),
+ iColour(pCopy->bVisible ? pCopy->iColour : iBkgCol), bVisible(pCopy->bVisible || (iBkgCol!=-1)),
+ iNumChildNodes(pCopy->iNumChildNodes), pLabel(strLabel.empty() ? NULL : pScreen->MakeLabel(strLabel)) {
+}
+
+CAlphabetManager::SGroupInfo::~SGroupInfo() {
+ delete pChild;
+ delete pNext;
+ delete pLabel;
+}
+
+CAlphabetManager::SGroupInfo *CAlphabetManager::copyGroups(CDasherScreen *pScreen, int iStart, int iEnd, ::SGroupInfo *pFirstChild) {
+ for (int i = iStart; i< iEnd; i++) {
+ string strGroupPrefix;
+ if (pFirstChild && i>=pFirstChild->iStart) {
+ //reached group. elide any group with only a single child (see below).
+ // Variables store necessary properties of any elided groups:
+ int iBkgCol(-1);
+ for (const ::SGroupInfo *pInner=pFirstChild;;) {
+ if (pInner->iNumChildNodes>1) { //in/reached nontrivial subgroup - do make node for entire group:
+ SGroupInfo *pRes = new SGroupInfo(pScreen, strGroupPrefix, iBkgCol, pInner);
+ pRes->pChild = copyGroups(pScreen, pInner->iStart, pInner->iEnd, pInner->pChild);
+ pRes->pNext = copyGroups(pScreen, pInner->iEnd, iEnd, pFirstChild->pNext);
+ return pRes;
+ }
+ //were about to create a group node, which would have only one child
+ // (eventually, if the group node were PopulateChildren'd).
+ // Such a child would entirely fill it's parent (the group), and thus,
+ // creation/destruction of the child would cause the node's colour to flash
+ // between that for parent group and child.
+ // Hence, instead we elide the group node and create the child _here_...
+
+ //1. however we also have to take account of the appearance of the elided group. Hence:
+ strGroupPrefix += pInner->strLabel;
+ if (pInner->bVisible) iBkgCol=pInner->iColour;
+ //2. inner group might contain a single subgroup, or a single symbol...
+ if (!pInner->pChild) break;
+ //...a subgroup, so go into it
+ pInner = pInner->pChild;
+ DASHER_ASSERT(!pInner->pNext);
+ //3. loop round inner loop...
+ }
+ pFirstChild = pFirstChild->pNext; //making a symbol, so we've still moved past the outer (elided) group
+ }
+ m_vLabels[i]=pScreen->MakeLabel(strGroupPrefix+m_pAlphabet->GetDisplayText(i));
+ }
+ return NULL;
+}
+
const CAlphInfo *CAlphabetManager::GetAlphabet() const {
return m_pAlphabet;
}
@@ -144,8 +204,8 @@ int CAlphabetManager::GetColour(symbol sym, int iOffset) const {
}
-CAlphabetManager::CAlphBase::CAlphBase(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CAlphabetManager *pMgr)
-: CDasherNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText), m_pMgr(pMgr) {
+CAlphabetManager::CAlphBase::CAlphBase(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CAlphabetManager *pMgr)
+: CDasherNode(pParent, iOffset, iLbnd, iHbnd, iColour, pLabel), m_pMgr(pMgr) {
}
void CAlphabetManager::CAlphBase::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int iNormalization) {
@@ -159,23 +219,23 @@ void CAlphabetManager::CAlphBase::Output(Dasher::VECTOR_SYMBOL_PROB* pAdded, int
void CAlphabetManager::CAlphBase::Undo(int *pNumDeleted) {
if (m_pMgr->m_pLastOutput==this) m_pMgr->m_pLastOutput = Parent();
}
-CAlphabetManager::CAlphNode::CAlphNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CAlphabetManager *pMgr)
-: CAlphBase(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText, pMgr), m_pProbInfo(NULL) {
+CAlphabetManager::CAlphNode::CAlphNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CAlphabetManager *pMgr)
+: CAlphBase(pParent, iOffset, iLbnd, iHbnd, iColour, pLabel, pMgr), m_pProbInfo(NULL) {
}
-CAlphabetManager::CSymbolNode::CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CAlphabetManager *pMgr, symbol _iSymbol)
-: CAlphNode(pParent, iOffset, iLbnd, iHbnd, pMgr->GetColour(_iSymbol, iOffset), strGroup+pMgr->m_pAlphabet->GetDisplayText(_iSymbol), pMgr), iSymbol(_iSymbol) {
+CAlphabetManager::CSymbolNode::CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CDasherScreen::Label *pLabel, CAlphabetManager *pMgr, symbol _iSymbol)
+: CAlphNode(pParent, iOffset, iLbnd, iHbnd, pMgr->GetColour(_iSymbol, iOffset), pLabel, pMgr), iSymbol(_iSymbol) {
}
-CAlphabetManager::CSymbolNode::CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CAlphabetManager *pMgr, symbol _iSymbol)
-: CAlphNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText, pMgr), iSymbol(_iSymbol) {
+CAlphabetManager::CSymbolNode::CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CAlphabetManager *pMgr, symbol _iSymbol)
+: CAlphNode(pParent, iOffset, iLbnd, iHbnd, iColour, pLabel, pMgr), iSymbol(_iSymbol) {
}
-CAlphabetManager::CGroupNode::CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, CAlphabetManager *pMgr, const SGroupInfo *pGroup)
+CAlphabetManager::CGroupNode::CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CDasherScreen::Label *pLabel, int iBkgCol, CAlphabetManager *pMgr, const SGroupInfo *pGroup)
: CAlphNode(pParent, iOffset, iLbnd, iHbnd,
pGroup ? (pGroup->bVisible ? pGroup->iColour : iBkgCol)
: (iOffset&1) ? 7 : 137, //special case for root nodes
- pGroup ? strEnc+pGroup->strLabel : strEnc, pMgr), m_pGroup(pGroup) {
+ pLabel, pMgr), m_pGroup(pGroup) {
}
CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, bool bEnteredLast, int iOffset) {
@@ -187,12 +247,12 @@ CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, uns
CAlphNode *pNewNode;
if(p.first==0 || !bEnteredLast) {
//couldn't extract last symbol (so probably using default context), or shouldn't
- pNewNode = new CGroupNode(pParent, iNewOffset, iLower, iUpper, "", 0, this, NULL); //default background colour
+ pNewNode = new CGroupNode(pParent, iNewOffset, iLower, iUpper, NULL, 0, this, NULL); //default background colour
} else {
//new node represents a symbol that's already happened - i.e. user has already steered through it;
// so either we're rebuilding, or else creating a new root from existing text (in edit box)
DASHER_ASSERT(!pParent);
- pNewNode = new CSymbolNode(pParent, iNewOffset, iLower, iUpper, "", this, p.first);
+ pNewNode = new CSymbolNode(pParent, iNewOffset, iLower, iUpper, m_vLabels[p.first], this, p.first);
}
pNewNode->iContext = p.second;
@@ -337,12 +397,12 @@ int CAlphabetManager::CGroupNode::ExpectedNumChildren() {
return (m_pGroup) ? m_pGroup->iNumChildNodes : CAlphNode::ExpectedNumChildren();
}
-CAlphabetManager::CGroupNode *CAlphabetManager::CreateGroupNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo) {
+CAlphabetManager::CGroupNode *CAlphabetManager::CreateGroupNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, int iBkgCol, const SGroupInfo *pInfo) {
// When creating a group node...
// ...the offset is the same as the parent...
- CGroupNode *pNewNode = new CGroupNode(pParent, pParent->offset(), iLbnd, iHbnd, strEnc, iBkgCol, this, pInfo);
+ CGroupNode *pNewNode = new CGroupNode(pParent, pParent->offset(), iLbnd, iHbnd, pInfo->pLabel, iBkgCol, this, pInfo);
//...as is the context!
pNewNode->iContext = m_pLanguageModel->CloneContext(pParent->iContext);
@@ -350,8 +410,8 @@ CAlphabetManager::CGroupNode *CAlphabetManager::CreateGroupNode(CAlphNode *pPare
return pNewNode;
}
-CDasherNode *CAlphabetManager::CAlphBase::RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo) {
- CGroupNode *pRet=m_pMgr->CreateGroupNode(pParent, iLbnd, iHbnd, strEnc, iBkgCol, pInfo);
+CDasherNode *CAlphabetManager::CAlphBase::RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, int iBkgCol, const SGroupInfo *pInfo) {
+ CGroupNode *pRet=m_pMgr->CreateGroupNode(pParent, iLbnd, iHbnd, iBkgCol, pInfo);
if (isInGroup(pInfo)) {
//created group node should contain this one
m_pMgr->IterateChildGroups(pRet,pInfo,this);
@@ -359,7 +419,7 @@ CDasherNode *CAlphabetManager::CAlphBase::RebuildGroup(CAlphNode *pParent, unsig
return pRet;
}
-CDasherNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo) {
+CDasherNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, int iBkgCol, const SGroupInfo *pInfo) {
if (pInfo == m_pGroup) {
SetRange(iLbnd, iHbnd);
SetParent(pParent);
@@ -367,7 +427,7 @@ CDasherNode *CAlphabetManager::CGroupNode::RebuildGroup(CAlphNode *pParent, unsi
DASHER_ASSERT (offset() == pParent->offset());
return this;
}
- return CAlphBase::RebuildGroup(pParent, iLbnd, iHbnd, strEnc, iBkgCol, pInfo);
+ return CAlphBase::RebuildGroup(pParent, iLbnd, iHbnd, iBkgCol, pInfo);
}
bool CAlphabetManager::CGroupNode::isInGroup(const SGroupInfo *pInfo) {
@@ -378,7 +438,7 @@ bool CAlphabetManager::CSymbolNode::isInGroup(const SGroupInfo *pInfo) {
return (pInfo->iStart <= iSymbol && pInfo->iEnd > iSymbol);
}
-CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
+CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol) {
// TODO: Exceptions / error handling in general
@@ -386,7 +446,7 @@ CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, unsigned int
// (and we can't call numChars() on the symbol before we've constructed it!)
int iNewOffset = pParent->offset()+1;
if (m_pAlphabet->GetText(iSymbol)=="\r\n") iNewOffset++;
- CSymbolNode *pAlphNode = new CSymbolNode(pParent, iNewOffset, iLbnd, iHbnd, "", this, iSymbol);
+ CSymbolNode *pAlphNode = new CSymbolNode(pParent, iNewOffset, iLbnd, iHbnd, m_vLabels[iSymbol], this, iSymbol);
// std::stringstream ssLabel;
@@ -400,18 +460,18 @@ CDasherNode *CAlphabetManager::CreateSymbolNode(CAlphNode *pParent, unsigned int
return pAlphNode;
}
-CDasherNode *CAlphabetManager::CAlphBase::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
- return m_pMgr->CreateSymbolNode(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
+CDasherNode *CAlphabetManager::CAlphBase::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol) {
+ return m_pMgr->CreateSymbolNode(pParent, iLbnd, iHbnd, iSymbol);
}
-CDasherNode *CAlphabetManager::CSymbolNode::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
+CDasherNode *CAlphabetManager::CSymbolNode::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol) {
if(iSymbol == this->iSymbol) {
SetRange(iLbnd, iHbnd);
SetParent(pParent);
DASHER_ASSERT(offset() == pParent->offset() + numChars());
return this;
}
- return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
+ return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, iSymbol);
}
void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, const SGroupInfo *pParentGroup, CAlphBase *buildAround) {
@@ -427,7 +487,7 @@ void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, const SGroupInfo *
// Create child nodes and add them
int i(iMin); //lowest index of child which we haven't yet added
- const SGroupInfo *pCurrentNode(pParentGroup ? pParentGroup->pChild : m_pAlphabet->m_pBaseGroup);
+ const SGroupInfo *pCurrentNode(pParentGroup ? pParentGroup->pChild : m_pFirstGroup);
// The SGroupInfo structure has something like linked list behaviour
// Each SGroupInfo contains a pNext, a pointer to a sibling group info
while (i < iMax) {
@@ -442,38 +502,15 @@ void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, const SGroupInfo *
unsigned int iHbnd = (((*pCProb)[iEnd-1] - (*pCProb)[iMin-1]) *
(uint64)(m_pNCManager->GetLongParameter(LP_NORMALIZATION))) /
iRange;
- //loop for eliding groups with single children (see below).
- // Variables store necessary properties of any elided groups:
- std::string groupPrefix=""; int iBackgroundColour=pParent->getColour();
- const SGroupInfo *pInner=pCurrentNode;
- while (true) {
- if (bSymbol) {
- pNewChild = (buildAround) ? buildAround->RebuildSymbol(pParent, iLbnd, iHbnd, groupPrefix, iBackgroundColour, i) : CreateSymbolNode(pParent, iLbnd, iHbnd, groupPrefix, iBackgroundColour, i);
- i++; //make one symbol at a time - move onto next symbol in next iteration of (outer) loop
- break; //exit inner (group elision) loop
- } else if (pInner->iNumChildNodes>1) { //in/reached nontrivial subgroup - do make node for entire group:
- pNewChild= (buildAround) ? buildAround->RebuildGroup(pParent, iLbnd, iHbnd, groupPrefix, iBackgroundColour, pInner) : CreateGroupNode(pParent, iLbnd, iHbnd, groupPrefix, iBackgroundColour, pInner);
- i = pInner->iEnd; //make one group at a time - so move past entire group...
- pCurrentNode = pCurrentNode->pNext; //next sibling of _original_ pCurrentNode (above)
- // (maybe not of pCurrentNode now, which might be a subgroup filling the original)
- break; //exit inner (group elision) loop
- }
- //were about to create a group node, which would have only one child
- // (eventually, if the group node were PopulateChildren'd).
- // Such a child would entirely fill it's parent (the group), and thus,
- // creation/destruction of the child would cause the node's colour to flash
- // between that for parent group and child.
- // Hence, instead we elide the group node and create the child _here_...
-
- //1. however we also have to take account of the appearance of the elided group. Hence:
- groupPrefix += pInner->strLabel;
- if (pInner->bVisible) iBackgroundColour=pInner->iColour;
- //2. now go into the group...
- pInner = pInner->pChild;
- bSymbol = (pInner==NULL); //which might contain a single subgroup, or a single symbol
- if (bSymbol) pCurrentNode = pCurrentNode->pNext; //if a symbol, we've still moved past the outer (elided) group
- DASHER_ASSERT(iEnd == (bSymbol ? i+1 : pInner->iEnd)); //probability calcs still ok
- //3. loop round inner loop...
+ if (bSymbol) {
+ pNewChild = (buildAround) ? buildAround->RebuildSymbol(pParent, iLbnd, iHbnd, i) : CreateSymbolNode(pParent, iLbnd, iHbnd, i);
+ i++; //make one symbol at a time - move onto next symbol in next iteration of (outer) loop
+ } else {
+ DASHER_ASSERT(pCurrentNode->iNumChildNodes > 1);
+ pNewChild= (buildAround) ? buildAround->RebuildGroup(pParent, iLbnd, iHbnd, pParent->getColour(), pCurrentNode) : CreateGroupNode(pParent, iLbnd, iHbnd, pParent->getColour(), pCurrentNode);
+ i = pCurrentNode->iEnd; //make one group at a time - so move past entire group...
+ pCurrentNode = pCurrentNode->pNext; //next sibling of _original_ pCurrentNode (above)
+ // (maybe not of pCurrentNode now, which might be a subgroup filling the original)
}
//created a new node - symbol or (group which will have >1 child).
DASHER_ASSERT(pParent->GetChildren().back()==pNewChild);
@@ -564,7 +601,7 @@ CDasherNode *CAlphabetManager::CGroupNode::RebuildParent() {
if (Parent()) return Parent();
// CGroupNodes with an m_pGroup have a container i.e. the parent group, unless
- // m_pGroup==NULL => "root" node where Alphabet->m_pBaseGroup is the *first*child*...
+ // m_pGroup==NULL => "root" node where m_pMgr->m_pFirstGroup is the *first*child*...
if (m_pGroup == NULL) return NULL;
return CAlphBase::RebuildParent();
diff --git a/Src/DasherCore/AlphabetManager.h b/Src/DasherCore/AlphabetManager.h
index a587d57..50d5f9a 100644
--- a/Src/DasherCore/AlphabetManager.h
+++ b/Src/DasherCore/AlphabetManager.h
@@ -48,10 +48,12 @@ namespace Dasher {
public:
///Create a new AlphabetManager. Note, not usable until CreateLanguageModel() called.
CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, const CAlphabetMap *pAlphabetMap);
+
///Creates the LM, and stores in m_pLanguageModel. Must be called after construction,
/// before the AlphMgr is used. Default implementation switches on LP_LANGUAGE_MODEL_ID.
virtual void CreateLanguageModel(CEventHandler *pEventHandler, CSettingsStore *pSets);
+ virtual void MakeLabels(CDasherScreen *pScreen);
///Gets a new trainer to train this LM. Caller is responsible for deallocating the
/// trainer later.
virtual CTrainer *GetTrainer();
@@ -61,6 +63,25 @@ namespace Dasher {
/// \param pInterface to use for I/O by calling WriteTrainFile(fname,txt)
void WriteTrainFileFull(CDasherInterfaceBase *pInterface);
protected:
+ ///The SGroupInfo tree from the alphabet, but with single-child groups collapsed,
+ /// and with labels from the Screen.
+ struct SGroupInfo {
+ SGroupInfo(CDasherScreen *pScreen, const std::string &strEnc, int iBkgCol, const ::SGroupInfo *pCopy);
+ ~SGroupInfo();
+ SGroupInfo *pChild;
+ SGroupInfo *pNext;
+ std::string strLabel;
+ int iStart;
+ int iEnd;
+ int iColour;
+ bool bVisible;
+ int iNumChildNodes;
+ CDasherScreen::Label *pLabel;
+ } *m_pFirstGroup;
+ //A label for each symbol, indexed by symbol id (element 0 = null)
+ std::vector<CDasherScreen::Label *> m_vLabels;
+ SGroupInfo *copyGroups(CDasherScreen *pScreen, int iStart, int iEnd, ::SGroupInfo *pFirstChild);
+
class CAlphNode;
/// Abstract superclass for alphabet manager nodes, provides common implementation
/// code for rebuilding parent nodes = reversing.
@@ -74,18 +95,15 @@ namespace Dasher {
/// Default implementation just calls the manager's CreateSymbolNode method to create a new node,
/// but subclasses can override to graft themselves into the appropriate point beneath the previous node.
/// \param pParent parent of the symbol node to create; could be the previous root, or an intervening node (e.g. group)
- /// \param strGroup caption of any elided group node. If a new node is created, this should be appended to that node's caption;
- /// however, if this existing node is grafted in instead, the caption will already have been prepended (as the group structure
- /// is always the same and just repeats endlessly), so should be ignored.
/// \param iBkgCol background colour to show through any new transparent node created;
/// if the existing node is grafted in, again this will already have been taken into account.
- virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+ virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol);
///Called to build a group node which is a descendant of the symbol or root node preceding this.
/// Default implementation calls the manager's CreateGroupNode method to create a new node,
/// but then populates that group (i.e. further descends the hierarchy) _if_ that group
/// would contain this node (see IsInGroup). Subclasses can override to graft themselves into the hierarchy, if appropriate.
/// \param pParent parent of the symbol node to create; could be the previous root, or an intervening node (e.g. group)
- virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo);
+ virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, int iBkgCol, const SGroupInfo *pInfo);
///Just keep track of the last node output (for training file purposes)
void Undo(int *pNumDeleted);
///Just keep track of the last node output (for training file purposes)
@@ -97,7 +115,7 @@ namespace Dasher {
/// at which point RebuildSymbol/Group should graft it in.
/// \param pNewNode newly-created root node beneath which this node should fit
virtual void RebuildForwardsFromAncestor(CAlphNode *pNewNode);
- CAlphBase(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText, CAlphabetManager *pMgr);
+ CAlphBase(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CAlphabetManager *pMgr);
CAlphabetManager *m_pMgr;
///Number of unicode characters entered by this node; i.e., the number
/// to take off this node's offset, to get the offset of the most-recent
@@ -107,11 +125,10 @@ namespace Dasher {
/// (as a symbol or subgroup), any number of levels beneath it
virtual bool isInGroup(const SGroupInfo *pGroup)=0;
};
-
///Additionally stores LM contexts and probabilities calculated therefrom
class CAlphNode : public CAlphBase {
public:
- CAlphNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText, CAlphabetManager *pMgr);
+ CAlphNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CAlphabetManager *pMgr);
CLanguageModel::Context iContext;
///
/// Delete any storage alocated for this node
@@ -127,10 +144,8 @@ namespace Dasher {
class CSymbolNode : public CAlphNode {
public:
///Standard constructor, gets colour from GetColour(symbol,offset) and label from current alphabet
- /// \param strGroup caption of any enclosing group(s) of which this symbol is a singleton child
- /// - this is prepended onto the symbol caption. Note, we don't need the "background colour" of
- /// any such group, as GetColour() always returns an opaque color.
- CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CAlphabetManager *pMgr, symbol iSymbol);
+ /// Note we treat GetColour() as always returning an opaque color.
+ CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CDasherScreen::Label *pLabel, CAlphabetManager *pMgr, symbol iSymbol);
///Create the children of this node, by starting traversal of the alphabet from the top
virtual void PopulateChildren();
@@ -143,7 +158,7 @@ namespace Dasher {
virtual void GetContext(CDasherInterfaceBase *pInterface, const CAlphabetMap *pAlphabetMap, std::vector<symbol> &vContextSymbols, int iOffset, int iLength);
virtual symbol GetAlphSymbol();
///Override: if the symbol to create is the same as this node's symbol, return this node instead of creating a new one
- virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+ virtual CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol);
protected:
virtual const std::string &outputText();
///Text to write to user training file/buffer when this symbol output.
@@ -155,7 +170,7 @@ namespace Dasher {
/// unicode char, even if that might take >1 octet.
int numChars();
///Compatibility constructor, so that subclasses can specify their own colour & label
- CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText, CAlphabetManager *pMgr, symbol _iSymbol);
+ CSymbolNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CAlphabetManager *pMgr, symbol _iSymbol);
///Override: true iff pGroup encloses this symbol (according to its start/end symbol#)
bool isInGroup(const SGroupInfo *pGroup);
const symbol iSymbol;
@@ -163,7 +178,7 @@ namespace Dasher {
class CGroupNode : public CAlphNode {
public:
- CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, CAlphabetManager *pMgr, const SGroupInfo *pGroup);
+ CGroupNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CDasherScreen::Label *pLabel, int iBkgCol, CAlphabetManager *pMgr, const SGroupInfo *pGroup);
///Override: if m_pGroup==NULL, i.e. whole/root-of alphabet, cannot rebuild.
virtual CDasherNode *RebuildParent();
@@ -175,7 +190,7 @@ namespace Dasher {
virtual bool GameSearchNode(std::string strTargetUtf8Char);
std::vector<unsigned int> *GetProbInfo();
///Override: if the group to create is the same as this node's group, return this node instead of creating a new one
- virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo);
+ virtual CDasherNode *RebuildGroup(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, int iBkgCol, const SGroupInfo *pInfo);
protected:
///Override: true if pGroup encloses this one (by start/end symbol#)
bool isInGroup(const SGroupInfo *pGroup);
@@ -207,11 +222,9 @@ namespace Dasher {
std::pair<symbol, CLanguageModel::Context> GetContextSymbols(CDasherNode *pParent, int iRootOffset, const CAlphabetMap *pAlphMap);
///Called to create a node for a given symbol (leaf), as a child of a specified parent node
- /// \param strGroup caption of any group containing this node, that will not be created:
- /// thus, should be prepended onto the caption of the node created.
- /// \param iBkgCol colour behind the new node, i.e. that should show through if the node is transparent
- virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
- virtual CGroupNode *CreateGroupNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strEnc, int iBkgCol, const SGroupInfo *pInfo);
+ /// \param iBkgCol colour behind the new node, i.e. that should show through if the (group) node is transparent
+ virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol);
+ virtual CGroupNode *CreateGroupNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, int iBkgCol, const SGroupInfo *pInfo);
///Called to compute colour for a symbol at a specified offset.
/// Wraps CAlphabet::GetColour(sym), but (a) implements a default
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index 0df295e..74b8b25 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -61,12 +61,34 @@ CDasherNode *CControlBase::GetRoot(CDasherNode *pParent, unsigned int iLower, un
return pNewNode;
}
+void CControlBase::MakeLabels(CDasherScreen *pScreen) {
+ deque<NodeTemplate *> templateQueue(1,m_pRoot);
+ set<NodeTemplate *> allTemplates(templateQueue.begin(),templateQueue.end());
+ while (!templateQueue.empty()) {
+ NodeTemplate *head = templateQueue.front();
+ templateQueue.pop_front();
+ delete head->m_pLabel;
+ head->m_pLabel = pScreen->MakeLabel(head->m_strLabel);
+ for (vector<NodeTemplate *>::iterator it = head->successors.begin(); it!=head->successors.end(); it++) {
+ if (!(*it)) continue; //an escape back to the alphabet, no label/successors here
+ if (allTemplates.find(*it)==allTemplates.end()) {
+ allTemplates.insert(*it);
+ templateQueue.push_back(*it);
+ }
+ }
+ }
+}
+
CControlBase::NodeTemplate::NodeTemplate(const string &strLabel,int iColour)
-: m_strLabel(strLabel), m_iColour(iColour) {
+: m_strLabel(strLabel), m_iColour(iColour), m_pLabel(NULL) {
+}
+
+CControlBase::NodeTemplate::~NodeTemplate() {
+ delete m_pLabel;
}
CControlBase::CContNode::CContNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, NodeTemplate *pTemplate, CControlBase *pMgr)
-: CDasherNode(pParent, iOffset, iLbnd, iHbnd, (pTemplate->colour() != -1) ? pTemplate->colour() : (pParent->ChildCount()%99)+11, pTemplate->label()), m_pTemplate(pTemplate), m_pMgr(pMgr) {
+: CDasherNode(pParent, iOffset, iLbnd, iHbnd, (pTemplate->m_iColour != -1) ? pTemplate->m_iColour : (pParent->ChildCount()%99)+11, pTemplate->m_pLabel), m_pTemplate(pTemplate), m_pMgr(pMgr) {
}
void CControlBase::CContNode::PopulateChildren() {
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index 828f279..42ffa27 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -87,13 +87,13 @@ namespace Dasher {
class NodeTemplate : public Action {
public:
NodeTemplate(const std::string &strLabel, int iColour);
- virtual ~NodeTemplate() {}
- int colour() {return m_iColour;};
- const std::string &label() {return m_strLabel;};
+ virtual ~NodeTemplate();
+ const std::string m_strLabel;
+ const int m_iColour;
std::vector<NodeTemplate *> successors;
private:
- std::string m_strLabel;
- int m_iColour;
+ friend class CControlBase;
+ CDasherScreen::Label *m_pLabel;
};
template <typename T> class MethodTemplate : public NodeTemplate {
@@ -115,6 +115,9 @@ namespace Dasher {
CControlBase(CNodeCreationManager *pNCManager);
+ ///Make this manager ready to make nodes renderable on the screen by preallocating labels
+ virtual void MakeLabels(CDasherScreen *pScreen);
+
///
/// Get a new root node owned by this manager
///
diff --git a/Src/DasherCore/ConversionHelper.cpp b/Src/DasherCore/ConversionHelper.cpp
index 305ba3e..e453063 100644
--- a/Src/DasherCore/ConversionHelper.cpp
+++ b/Src/DasherCore/ConversionHelper.cpp
@@ -121,7 +121,7 @@ void CConversionHelper::CConvHNode::PopulateChildren() {
// std::cout << "#" << pCurrentSCEChild->pszConversion << "#" << std::endl;
- CConvNode *pNewNode = mgr()->makeNode(this, offset()+1, iLbnd, iHbnd, mgr()->AssignColour(parentClr, pCurrentSCEChild, iIdx), string(pCurrentSCEChild->pszConversion));
+ CConvNode *pNewNode = mgr()->makeNode(this, offset()+1, iLbnd, iHbnd, mgr()->AssignColour(parentClr, pCurrentSCEChild, iIdx), mgr()->GetLabel(pCurrentSCEChild->pszConversion));
// TODO: Reimplement ----
@@ -190,13 +190,13 @@ void CConversionHelper::BuildTree(CConvHNode *pRoot) {
pRoot->pSCENode = pStartTemp;
}
-CConversionHelper::CConvHNode::CConvHNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CConversionHelper *pMgr)
-: CConvNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText, pMgr) {
+CConversionHelper::CConvHNode::CConvHNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CConversionHelper *pMgr)
+: CConvNode(pParent, iOffset, iLbnd, iHbnd, iColour, pLabel, pMgr) {
}
-CConversionHelper::CConvHNode *CConversionHelper::makeNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText) {
- return new CConvHNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText, this);
+CConversionHelper::CConvHNode *CConversionHelper::makeNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel) {
+ return new CConvHNode(pParent, iOffset, iLbnd, iHbnd, iColour, pLabel, this);
}
void CConversionHelper::CConvHNode::SetFlag(int iFlag, bool bValue) {
diff --git a/Src/DasherCore/ConversionHelper.h b/Src/DasherCore/ConversionHelper.h
index ca5aa16..b3c39cd 100644
--- a/Src/DasherCore/ConversionHelper.h
+++ b/Src/DasherCore/ConversionHelper.h
@@ -26,6 +26,7 @@
#include <vector>
#include "SCENode.h"
#include "LanguageModelling/LanguageModel.h"
+#include "DasherScreen.h"
namespace Dasher{
class CDasherNode; //forward declaration
@@ -42,7 +43,7 @@ namespace Dasher{
class CConversionHelper : public CConversionManager {
public:
CConversionHelper(CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, CLanguageModel *pLanguageModel);
-
+
/// Convert a given string to a lattice of candidates. Sizes for
/// candidates aren't assigned at this point. The input string
/// should be UTF-8 encoded.
@@ -111,7 +112,7 @@ namespace Dasher{
protected:
class CConvHNode : public CConvNode {
public:
- CConvHNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText, CConversionHelper *pMgr);
+ CConvHNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CConversionHelper *pMgr);
///
/// Provide children for the supplied node
///
@@ -121,7 +122,7 @@ namespace Dasher{
protected:
inline CConversionHelper *mgr() {return static_cast<CConversionHelper *>(m_pMgr);}
};
- virtual CConvHNode *makeNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText);
+ virtual CConvHNode *makeNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel);
///
/// Build the conversion tree (lattice) for the given string -
/// evaluated late to prevent unnecessary conversions when the
@@ -133,7 +134,7 @@ namespace Dasher{
virtual Dasher::CLanguageModel *GetLanguageModel() {
return m_pLanguageModel;
}
-
+
private:
CLanguageModel *m_pLanguageModel;
diff --git a/Src/DasherCore/ConversionManager.cpp b/Src/DasherCore/ConversionManager.cpp
index 65b0755..8703807 100644
--- a/Src/DasherCore/ConversionManager.cpp
+++ b/Src/DasherCore/ConversionManager.cpp
@@ -56,8 +56,23 @@ CConversionManager::CConversionManager(CNodeCreationManager *pNCManager, const C
*/
}
-CConversionManager::CConvNode *CConversionManager::makeNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText) {
- return new CConvNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText, this);
+CConversionManager::CConvNode *CConversionManager::makeNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel) {
+ return new CConvNode(pParent, iOffset, iLbnd, iHbnd, iColour, pLabel, this);
+}
+
+void CConversionManager::ChangeScreen(CDasherScreen *pScreen) {
+ if (m_pScreen==pScreen) return;
+ for (map<string, CDasherScreen::Label *>::iterator it=m_vLabels.begin(); it!=m_vLabels.end(); it++)
+ delete it->second;
+ m_vLabels.clear();
+ m_pScreen=pScreen;
+}
+
+CDasherScreen::Label *CConversionManager::GetLabel(const char *pszConversion) {
+ string strConv(pszConversion);
+ if (m_vLabels[strConv])
+ return m_vLabels[strConv];
+ return m_vLabels[strConv] = m_pScreen->MakeLabel(strConv);
}
CConversionManager::CConvNode *CConversionManager::GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, int iOffset) {
@@ -65,7 +80,7 @@ CConversionManager::CConvNode *CConversionManager::GetRoot(CDasherNode *pParent,
// TODO: Parameters here are placeholders - need to figure out what's right
//TODO: hard-coded colour, and hard-coded displaytext... (ACL: read from Alphabet -> startConversionSymbol ?)
- CConvNode *pNewNode = makeNode(pParent, iOffset, iLower, iUpper, 9, "");
+ CConvNode *pNewNode = makeNode(pParent, iOffset, iLower, iUpper, 9, NULL);
// FIXME - handle context properly
// TODO: Reimplemnt -----
@@ -82,8 +97,8 @@ CConversionManager::CConvNode *CConversionManager::GetRoot(CDasherNode *pParent,
return pNewNode;
}
-CConversionManager::CConvNode::CConvNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText, CConversionManager *pMgr)
- : CDasherNode(pParent, iOffset, iLbnd, iHbnd, iColour, strDisplayText), m_pMgr(pMgr) {
+CConversionManager::CConvNode::CConvNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CConversionManager *pMgr)
+ : CDasherNode(pParent, iOffset, iLbnd, iHbnd, iColour, pLabel), m_pMgr(pMgr) {
pMgr->m_iRefCount++;
}
diff --git a/Src/DasherCore/ConversionManager.h b/Src/DasherCore/ConversionManager.h
index 4bbd531..ab89a8f 100644
--- a/Src/DasherCore/ConversionManager.h
+++ b/Src/DasherCore/ConversionManager.h
@@ -63,6 +63,10 @@ namespace Dasher {
// TODO: We shouldn't need to know about this stuff, but the code is somewhat in knots at the moment
CConversionManager(CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet);
+ ///Tells us to use the specified screen to create node labels.
+ /// (note we cache the screen and create labels lazily)
+ void ChangeScreen(CDasherScreen *pScreen);
+
///
/// Decrement reference count
///
@@ -83,7 +87,7 @@ namespace Dasher {
class CConvNode : public CDasherNode {
public:
CConversionManager *mgr() {return m_pMgr;}
- CConvNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText, CConversionManager *pMgr);
+ CConvNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel, CConversionManager *pMgr);
///
/// Provide children for the supplied node
///
@@ -131,14 +135,21 @@ namespace Dasher {
virtual CConvNode *GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, int iOffset);
protected:
- virtual CConvNode *makeNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText);
+ virtual CConvNode *makeNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel);
CNodeCreationManager *m_pNCManager;
const CAlphInfo *m_pAlphabet;
+ ///Utility method for subclasses, lazily makes+caches node labels
+ /// \return a node label displaying the specified string
+ CDasherScreen::Label *GetLabel(const char *pszConversion);
+
private:
+ std::map<std::string, CDasherScreen::Label *> m_vLabels;
+ CDasherScreen *m_pScreen;
+
///
/// Dump tree to stdout (debug)
///
diff --git a/Src/DasherCore/ConvertingAlphMgr.cpp b/Src/DasherCore/ConvertingAlphMgr.cpp
index e2f28e3..487fada 100644
--- a/Src/DasherCore/ConvertingAlphMgr.cpp
+++ b/Src/DasherCore/ConvertingAlphMgr.cpp
@@ -16,11 +16,17 @@ CConvertingAlphMgr::CConvertingAlphMgr(CDasherInterfaceBase *pInterface, CNodeCr
: CAlphabetManager(pInterface, pNCManager, pAlphabet, pAlphabetMap), m_pConvMgr(pConvMgr) {
}
+void CConvertingAlphMgr::MakeLabels(CDasherScreen *pScreen) {
+ CAlphabetManager::MakeLabels(pScreen);
+ m_pConvMgr->ChangeScreen(pScreen);
+}
+
+
CConvertingAlphMgr::~CConvertingAlphMgr() {
m_pConvMgr->Unref();
}
-CDasherNode *CConvertingAlphMgr::CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const string &strGroup, int iBkgCol, symbol iSymbol) {
+CDasherNode *CConvertingAlphMgr::CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol) {
int i=m_pAlphabet->GetNumberTextSymbols()+1;
if (iSymbol == i) {
vector<unsigned int> *pCProb(pParent->GetProbInfo());
@@ -28,6 +34,6 @@ CDasherNode *CConvertingAlphMgr::CreateSymbolNode(CAlphNode *pParent, unsigned i
//ACL setting m_iOffset+1 for consistency with "proper" symbol nodes...
return m_pConvMgr->GetRoot(pParent, (*pCProb)[i-1], (*pCProb)[i], pParent->offset()+1);
} else {
- return CAlphabetManager::CreateSymbolNode(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
+ return CAlphabetManager::CreateSymbolNode(pParent, iLbnd, iHbnd, iSymbol);
}
}
diff --git a/Src/DasherCore/ConvertingAlphMgr.h b/Src/DasherCore/ConvertingAlphMgr.h
index d6e4501..59dafc5 100644
--- a/Src/DasherCore/ConvertingAlphMgr.h
+++ b/Src/DasherCore/ConvertingAlphMgr.h
@@ -23,10 +23,12 @@ namespace Dasher {
class CConvertingAlphMgr : public CAlphabetManager {
public:
CConvertingAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CConversionManager *pConvMgr, const CAlphInfo *pAlphabet, const CAlphabetMap *pAlphabetMap);
+ ///Override to also tell the ConversionManager that the screen has changed.
+ void MakeLabels(CDasherScreen *pScreen);
virtual ~CConvertingAlphMgr();
protected:
///Override to return a conversion root for iSymbol==(one beyond last alphabet symbol)
- virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+ virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol);
private:
CConversionManager *m_pConvMgr;
diff --git a/Src/DasherCore/DasherInterfaceBase.cpp b/Src/DasherCore/DasherInterfaceBase.cpp
index 89bf202..517f7c7 100644
--- a/Src/DasherCore/DasherInterfaceBase.cpp
+++ b/Src/DasherCore/DasherInterfaceBase.cpp
@@ -122,8 +122,13 @@ CDasherInterfaceBase::CDasherInterfaceBase() {
}
void CDasherInterfaceBase::Realize() {
+
// TODO: What exactly needs to have happened by the time we call Realize()?
CreateSettingsStore();
+
+ //create a view, if we have a screen...
+ //if(GetLongParameter(LP_VIEW_ID) != -1)
+ ChangeView();
//create the model... (no nodes just yet)
m_pDasherModel = new CDasherModel(m_pEventHandler, m_pSettingsStore, this);
@@ -370,10 +375,13 @@ void CDasherInterfaceBase::CreateNCManager() {
//now create the new manager...
m_pNCManager = new CNodeCreationManager(this, m_pEventHandler, m_pSettingsStore, m_AlphIO);
- //and start a new tree of nodes from it (retaining old offset -
- // this will be a sensible default of 0 if no nodes previously existed).
- // This deletes the old tree of nodes...
- m_pDasherModel->SetOffset(m_pDasherModel->GetOffset(), m_pNCManager->GetAlphabetManager(), m_pDasherView, true);
+ if (m_DasherScreen) {
+ m_pNCManager->ChangeScreen(m_DasherScreen);
+ //and start a new tree of nodes from it (retaining old offset -
+ // this will be a sensible default of 0 if no nodes previously existed).
+ // This deletes the old tree of nodes...
+ m_pDasherModel->SetOffset(m_pDasherModel->GetOffset(), m_pNCManager->GetAlphabetManager(), m_pDasherView, true);
+ } //else, if there is no screen, the model should not contain any nodes from the old NCManager. (Assert, somehow?)
//...so now we can delete the old manager
delete pOldMgr;
@@ -610,15 +618,30 @@ void CDasherInterfaceBase::ChangeColours() {
}
void CDasherInterfaceBase::ChangeScreen(CDasherScreen *NewScreen) {
- // What does ChangeScreen do?
+
m_DasherScreen = NewScreen;
ChangeColours();
-
+
if(m_pDasherView != 0) {
- m_pDasherView->ChangeScreen(m_DasherScreen);
- } else if(GetLongParameter(LP_VIEW_ID) != -1) {
+ m_pDasherView->ChangeScreen(NewScreen);
+ ScreenResized(NewScreen);
+ } else if (m_pEventHandler && m_pSettingsStore) {
+ //no screen, but other essential components (created in Realize) present.
+ // IOW, (assume) we were delaying creating a View, until we had a screen...
ChangeView();
}
+
+ if (m_pNCManager) {
+ m_pNCManager->ChangeScreen(m_DasherScreen);
+ if (m_pDasherModel)
+ m_pDasherModel->SetOffset(m_pDasherModel->GetOffset(), m_pNCManager->GetAlphabetManager(), m_pDasherView, true);
+ }
+}
+
+void CDasherInterfaceBase::ScreenResized(CDasherScreen *pScreen) {
+ DASHER_ASSERT(pScreen == m_DasherScreen);
+ if (!m_pDasherView) return;
+ m_pDasherView->ScreenResized(m_DasherScreen);
PositionActionButtons();
BudgettingPolicy pol(GetLongParameter(LP_NODE_BUDGET)); //maintain budget, but allow arbitrary amount of work.
@@ -633,14 +656,14 @@ void CDasherInterfaceBase::ChangeView() {
// TODO: Actually respond to LP_VIEW_ID parameter (although there is only one view at the moment)
// removed condition that m_pDasherModel != 0. Surely the view can exist without the model?-pconlon
- if(m_DasherScreen != 0 /*&& m_pDasherModel != 0*/) {
+ if(m_DasherScreen != 0 /*&& m_pDasherModel != 0*/) {
delete m_pDasherView;
m_pDasherView = new CDasherViewSquare(m_pEventHandler, m_pSettingsStore, m_DasherScreen);
// Tell the Teacher which view we are using
if(GameMode::CDasherGameMode* pTeacher = GameMode::CDasherGameMode::GetTeacher())
- pTeacher->SetDasherView(m_pDasherView);
+ pTeacher->SetDasherView(m_pDasherView);
}
}
diff --git a/Src/DasherCore/DasherInterfaceBase.h b/Src/DasherCore/DasherInterfaceBase.h
index 893ef2d..a2485ba 100644
--- a/Src/DasherCore/DasherInterfaceBase.h
+++ b/Src/DasherCore/DasherInterfaceBase.h
@@ -287,10 +287,23 @@ public:
// std::vector<std::string>& GetLangModels();
// std::vector<std::string>& GetViews();
- /// Supply a new CDasherScreen object to do the rendering.
+ /// Supply a new CDasherScreen object onto which to render. Note this should
+ /// only be called (a) at startup, and (b) when the new screen is _significantly_
+ /// different from the old, rather than just a window resize: specifically, this means
+ /// the tree of nodes will be rebuilt with new Labels for the new screen; and in the future,
+ /// maybe also if things like colour depth, alpha transparency support, etc., change.
+ /// If the existing rendering setup should just scale to the new screen dimensions,
+ /// call ScreenResized() instead (we expect this to be the case most/all of the time,
+ /// and this method subsumes a call to ScreenResized.) Note, at startup, ChangeScreen
+ /// and Realize may occur in either order; if ChangeScreen comes after, Resize will create a
+ /// tree with null Labels, which will have to be rebuilt in the call to ChangeScreen.
/// \param NewScreen Pointer to the new CDasherScreen.
-
- void ChangeScreen(CDasherScreen * NewScreen); // We may change the widgets Dasher uses
+ void ChangeScreen(CDasherScreen * NewScreen);
+
+ ///Call when the screen dimensions have been changed, to recalculate scaling factors etc.
+ /// \param pScreen the screen whose dimensions have changed. TODO we expect this to be
+ /// the same one-and-only screen that we are using anyway, so remove parameter?
+ void ScreenResized(CDasherScreen *pScreen);
/// Train Dasher from a file
/// All traing data must be in UTF-8
diff --git a/Src/DasherCore/DasherNode.cpp b/Src/DasherCore/DasherNode.cpp
index ef247fe..fdae932 100644
--- a/Src/DasherCore/DasherNode.cpp
+++ b/Src/DasherCore/DasherNode.cpp
@@ -42,8 +42,8 @@ static int iNumNodes = 0;
int Dasher::currentNumNodeObjects() {return iNumNodes;}
//TODO this used to be inline - should we make it so again?
-CDasherNode::CDasherNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const string &strDisplayText)
-: m_pParent(pParent), m_iOffset(iOffset), m_iLbnd(iLbnd), m_iHbnd(iHbnd), m_iColour(iColour), m_strDisplayText(strDisplayText) {
+CDasherNode::CDasherNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel)
+: m_pParent(pParent), m_iLbnd(iLbnd), m_iHbnd(iHbnd), m_iOffset(iOffset), m_iColour(iColour), m_pLabel(pLabel) {
DASHER_ASSERT(iHbnd >= iLbnd);
if (pParent) {
diff --git a/Src/DasherCore/DasherNode.h b/Src/DasherCore/DasherNode.h
index f503208..b8bf2eb 100644
--- a/Src/DasherCore/DasherNode.h
+++ b/Src/DasherCore/DasherNode.h
@@ -27,6 +27,7 @@
#include "DasherTypes.h"
#include "NodeManager.h"
#include "Alphabet/AlphabetMap.h"
+#include "DasherScreen.h"
namespace Dasher {
class CDasherNode;
@@ -66,7 +67,7 @@ class Dasher::CDasherNode:private NoClones {
/// Colour; note invisible nodes just have the same colour as their parent.
/// (so we know what colour to use when their parents are deleted)
inline int getColour() {return m_iColour;}
- inline const std::string &getDisplayText() {return m_strDisplayText;}
+ inline CDasherScreen::Label *getLabel() {return m_pLabel;}
///Whether labels on child nodes should be displaced to the right of this node's label.
/// (Default implementation returns true, subclasses should override if appropriate)
virtual bool bShove() {return true;}
@@ -80,12 +81,13 @@ class Dasher::CDasherNode:private NoClones {
/// @brief Constructor
///
- /// @param pParent Parent of the new node
- /// @param iLbnd Lower bound of node within parent
- /// @param iHbnd Upper bound of node within parent
- /// @param pDisplayInfo Struct containing information on how to display the node
- ///
- CDasherNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, const std::string &strDisplayText);
+ /// \param pParent Parent of the new node; automatically adds to end of parent's child list
+ /// \param iOffset Index into text buffer of character to LHS of cursor _after_ this node is Output().
+ /// \param iLbnd Lower bound of node within parent
+ /// \param iHbnd Upper bound of node within parent
+ /// \param iColour background colour of node (for transparent nodes, same colour as parent)
+ /// \param pLabel label to render onto node, NULL if no label required.
+ CDasherNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, int iColour, CDasherScreen::Label *pLabel);
/// @brief Destructor
///
@@ -281,7 +283,7 @@ class Dasher::CDasherNode:private NoClones {
protected:
const int m_iColour;
- const std::string m_strDisplayText;
+ CDasherScreen::Label * m_pLabel;
};
/// @}
diff --git a/Src/DasherCore/DasherScreen.h b/Src/DasherCore/DasherScreen.h
index 95f4140..ee83a95 100644
--- a/Src/DasherCore/DasherScreen.h
+++ b/Src/DasherCore/DasherScreen.h
@@ -7,6 +7,7 @@
#include "DasherTypes.h"
#include "../DasherCore/ColourIO.h"
+#include <set>
// DJW20050505 - renamed DrawText to DrawString - windows defines DrawText as a macro and it's
// really hard to work around
@@ -14,11 +15,21 @@
namespace Dasher {
class CDasherScreen;
+ class CLabelListScreen;
class CDasherInterfaceBase;
}
/// \ingroup View
/// @{
+/// Abstract interface for drawing operations, implemented by platform-specific canvases.
+/// Instances have _mutable_ dimensions; changes should be reported to the
+/// interface's ScreenResized method.
+/// Note the DrawString and TextSize methods: these now take platform-specific
+/// Label objects returned from MakeLabel. Thus, it is up to external clients to
+/// cache and reuse Labels. (This replaces the previous scheme where these methods
+/// took arbitrary std::strings, which were cached in a hashmap internal to each
+/// platform's screen. The new scheme allows clients to control cache preloading
+/// and flushing.)
class Dasher::CDasherScreen
{
public:
@@ -49,14 +60,40 @@ public:
screenint x;
screenint y;
} point;
+
+ /// (Default implementation returns false)
+ ///\return true if this Screen can efficiently support fonts of many sizes (by continuous scaling);
+ /// false if clients should try to minimise the number of distinct font sizes required.
+ virtual bool MultiSizeFonts() {return false;}
+
+ ///Abstract class for objects representing strings that can be drawn on the screen.
+ /// Platform-specific instances are created by the MakeLabel(String) method, which
+ /// may then be passed to GetSize() and DrawText().
+ class Label {
+ friend class CDasherScreen;
+ protected:
+ Label(const std::string &strText) : m_strText(strText) {};
+ public:
+ const std::string m_strText;
+ ///Delete the label. This should free up any resources associated with
+ /// drawing the string onto the screen, e.g. layouts or textures.
+ virtual ~Label() {}
+ };
+
+ ///Make a label for use with this screen.
+ /// \param strText UTF8-encoded text.
+ virtual Label *MakeLabel(const std::string &strText) {return new Label(strText);}
- // DasherView asks for the width and height of the given UTF8 string at a requested height,
- // then it is able to sensibly specify the upper left corner in DrawString.
- //! Set Width and Height to those of the string at size Size
- virtual void TextSize(const std::string & String, screenint * Width, screenint * Height, int Size) = 0;
+ ///Get Width and Height of a Label previously created by MakeLabel. Note behaviour
+ /// undefined if the Label is not one returned from a call to MakeLabel _on_this_Screen_.
+ virtual std::pair<screenint,screenint> TextSize(Label *label, unsigned int iFontSize) = 0;
- //! Draw UTF8-encoded string String of size Size positioned at x1 and y1
- virtual void DrawString(const std::string & String, screenint x1, screenint y1, int Size, int iColour) = 0;
+ /// Draw a label at position (x1,y1)
+ /// \param label a Label previously created by MakeLabel. Note behaviour
+ /// undefined if the Label is not one returned from a call to MakeLabel _on_this_Screen_.
+ /// \param x Coordinate of top left corner (i.e., left hand side)
+ /// \param y Coordinate of top left corner (i.e., top)
+ virtual void DrawString(Label *label, screenint x, screenint y, unsigned int iFontSize, int iColour) = 0;
// Send a marker to indicate 'phases' of drawing.
@@ -112,10 +149,6 @@ public:
/// \param lineWidth thickness of outline; 0 or less => don't draw outline.
virtual void Polygon(point * Points, int Number, int fillColour, int outlineColour, int lineWidth) = 0;
- // Signal the screen when a frame is started and finished
- //! Signal that a frame is being started
- virtual void Blank() = 0;
-
//! Signal that a frame is finished - the screen should be updated
virtual void Display() = 0;
@@ -124,12 +157,52 @@ public:
/// \param pColourScheme A colour scheme that should be used
virtual void SetColourScheme(const Dasher::CColourIO::ColourInfo *pColourScheme) = 0;
-protected:
+private:
//! Width and height of the screen
- const screenint m_iWidth, m_iHeight;
+ screenint m_iWidth, m_iHeight;
- //! Pointer to a widget interface for communication with the core
- // CDasherInterfaceBase *m_pDasherInterface;
+protected:
+ ///Subclasses should call this if the canvas dimensions have changed.
+ /// It is up to subclasses to make sure they also call
+ /// ScreenResized on the intf.
+ void resize(screenint width, screenint height) {
+ m_iWidth = width; m_iHeight = height;
+ }
+};
+
+/// Subclass that preserves a list of all labels returned from MakeLabel
+/// (and not yet deleted) so that they can be mutated en mass (by further
+/// subclasses) if necessary. Note we have to return a new Labels each time,
+/// and cannot hash/flyweight together similar Labels, because _clients_ are
+/// in control of deletion.
+class Dasher::CLabelListScreen : public Dasher::CDasherScreen {
+protected:
+ CLabelListScreen(screenint width, screenint height) : CDasherScreen(width,height) {
+ }
+ class Label : public CDasherScreen::Label {
+ public: //to instances of CLabelListScreen and subclasses
+ Label(CLabelListScreen *pScreen, const std::string &strText)
+ : CDasherScreen::Label(strText), m_pScreen(pScreen) {
+ m_pScreen->m_sLabels.insert(this);
+ }
+ ~Label() {
+ std::set<Label *>::iterator it = m_pScreen->m_sLabels.find(this);
+ DASHER_ASSERT(it != m_pScreen->m_sLabels.end());
+ m_pScreen->m_sLabels.erase(it);
+ }
+ CLabelListScreen * const m_pScreen;
+ };
+ ///An iterator pointing to the first extant (non-deleted) label created
+ /// from this screen. This allows iteration through modifiable labels,
+ /// but without being able to access or hence modify the set.
+ std::set<Label *>::iterator LabelsBegin() {return m_sLabels.begin();}
+
+ ///An iterator pointing just beyond the last extant (non-deleted) label
+ /// created from this screen. This allows iteration through modifiable labels,
+ /// but without being able to access or hence modify the set.
+ std::set<Label *>::iterator LabelsEnd() {return m_sLabels.end();}
+private:
+ std::set<Label *> m_sLabels;
};
/// @}
diff --git a/Src/DasherCore/DasherView.h b/Src/DasherCore/DasherView.h
index f2c01e4..ebc6b10 100644
--- a/Src/DasherCore/DasherView.h
+++ b/Src/DasherCore/DasherView.h
@@ -84,10 +84,18 @@ public:
/// @}
- /// Change the screen - must be called if the Screen is replaced or resized
+ /// Change the screen - must be called if the Screen is replaced (not resized).
+ /// Default implementation just stores pointer. Note that a call to ChangeScreen
+ /// is usually followed by a call to ScreenResized as well, so stuff that only
+ /// depends on screen size/resolution can be done there instead.
/// \param NewScreen Pointer to the new CDasherScreen.
-
virtual void ChangeScreen(CDasherScreen * NewScreen);
+
+ ///Call when the screen dimensions have been changed, to recalculate scaling factors etc.
+ /// The default implementation does nothing.
+ /// \param pScreen the screen whose dimensions have changed. TODO we expect this to be
+ /// the same one-and-only screen that we are using anyway, so remove parameter?
+ virtual void ScreenResized(CDasherScreen *pScreen) {}
/// @name High level drawing
/// Drawing more complex structures, generally implemented by derived class
diff --git a/Src/DasherCore/DasherViewSquare.cpp b/Src/DasherCore/DasherViewSquare.cpp
index 8330ef7..1088e1b 100644
--- a/Src/DasherCore/DasherViewSquare.cpp
+++ b/Src/DasherCore/DasherViewSquare.cpp
@@ -62,7 +62,7 @@ CDasherViewSquare::CDasherViewSquare(CEventHandler *pEventHandler, CSettingsStor
: CDasherView(pEventHandler, pSettingsStore, DasherScreen), m_Y1(4), m_Y2(0.95 * GetLongParameter(LP_MAX_Y)), m_Y3(0.05 * GetLongParameter((LP_MAX_Y))), m_bVisibleRegionValid(false) {
//Note, nonlinearity parameters set in SetScaleFactor
- ChangeScreen(DasherScreen);
+ ScreenResized(DasherScreen);
}
CDasherViewSquare::~CDasherViewSquare() {}
@@ -148,7 +148,7 @@ CDasherNode *CDasherViewSquare::Render(CDasherNode *pRoot, myint iRootMin, myint
/// specified as two co-ordinates, intended to the be the corners of
/// the leading edge of the containing box.
-CDasherViewSquare::CTextString *CDasherViewSquare::DasherDrawText(myint iDasherMaxX, myint iDasherMidY, const std::string &sDisplayText, CTextString *pParent, int iColor) {
+CDasherViewSquare::CTextString *CDasherViewSquare::DasherDrawText(myint iDasherMaxX, myint iDasherMidY, CDasherScreen::Label *pLabel, CTextString *pParent, int iColor) {
screenint x,y;
Dasher2Screen(iDasherMaxX, iDasherMidY, x, y);
@@ -157,7 +157,7 @@ CDasherViewSquare::CTextString *CDasherViewSquare::DasherDrawText(myint iDasherM
int iSize = GetLongParameter(LP_DASHER_FONTSIZE);
{
const myint iMaxY(GetLongParameter(LP_MAX_Y));
- if (GetBoolParameter(BP_MULTISIZE_FONTS)) {
+ if (Screen()->MultiSizeFonts() && iSize>4) {
//font size maxes out at ((iMaxY*3)/2)+iMaxY)/iMaxY = 3/2*smallest
// which is reached when iDasherMaxX == iMaxY/2, i.e. the crosshair
iSize = ((min(iDasherMaxX*3,(iMaxY*3)/2) + iMaxY) * iSize) / iMaxY;
@@ -173,7 +173,7 @@ CDasherViewSquare::CTextString *CDasherViewSquare::DasherDrawText(myint iDasherM
}
}
- CTextString *pRet = new CTextString(sDisplayText, x, y, iSize, iColor);
+ CTextString *pRet = new CTextString(pLabel, x, y, iSize, iColor);
vector<CTextString *> &dest(pParent ? pParent->m_children : m_DelayedTexts);
dest.push_back(pRet);
return pRet;
@@ -187,13 +187,13 @@ void CDasherViewSquare::DoDelayedText(CTextString *pText) {
// across according to the aiMax array, but this needs Dasher co-ordinates, which were
// more easily available at CTextString creation time. If it really doesn't look as good,
// can put in extra calls to Screen2Dasher....
- screenint x(pText->m_ix), y(pText->m_iy), textWidth, textHeight;
- Screen()->TextSize(pText->m_String, &textWidth, &textHeight, pText->m_iSize);
+ screenint x(pText->m_ix), y(pText->m_iy);
+ pair<screenint,screenint> textDims=Screen()->TextSize(pText->m_pLabel, pText->m_iSize);
switch (orient) {
case Dasher::Opts::LeftToRight: {
- screenint iRight = x + textWidth;
+ screenint iRight = x + textDims.first;
if (iRight < Screen()->GetWidth()) {
- Screen()->DrawString(pText->m_String, x, y-textHeight/2, pText->m_iSize, pText->m_iColor);
+ Screen()->DrawString(pText->m_pLabel, x, y-textDims.second/2, pText->m_iSize, pText->m_iColor);
for (vector<CTextString *>::iterator it = pText->m_children.begin(); it!=pText->m_children.end(); it++) {
CTextString *pChild=*it;
pChild->m_ix = max(pChild->m_ix, iRight);
@@ -204,9 +204,9 @@ void CDasherViewSquare::DoDelayedText(CTextString *pText) {
break;
}
case Dasher::Opts::RightToLeft: {
- screenint iLeft = x-textWidth;
+ screenint iLeft = x-textDims.first;
if (iLeft>=0) {
- Screen()->DrawString(pText->m_String, x - textWidth, y-textHeight/2, pText->m_iSize, pText->m_iColor);
+ Screen()->DrawString(pText->m_pLabel, iLeft, y-textDims.second/2, pText->m_iSize, pText->m_iColor);
for (vector<CTextString *>::iterator it = pText->m_children.begin(); it!=pText->m_children.end(); it++) {
CTextString *pChild=*it;
pChild->m_ix = min(pChild->m_ix, iLeft);
@@ -217,9 +217,9 @@ void CDasherViewSquare::DoDelayedText(CTextString *pText) {
break;
}
case Dasher::Opts::TopToBottom: {
- screenint iBottom = y + textHeight;
+ screenint iBottom = y + textDims.second;
if (iBottom < Screen()->GetHeight()) {
- Screen()->DrawString(pText->m_String, x-textWidth/2, y, pText->m_iSize, pText->m_iColor);
+ Screen()->DrawString(pText->m_pLabel, x-textDims.first/2, y, pText->m_iSize, pText->m_iColor);
for (vector<CTextString *>::iterator it = pText->m_children.begin(); it!=pText->m_children.end(); it++) {
CTextString *pChild=*it;
pChild->m_iy = max(pChild->m_iy, iBottom);
@@ -230,9 +230,9 @@ void CDasherViewSquare::DoDelayedText(CTextString *pText) {
break;
}
case Dasher::Opts::BottomToTop: {
- screenint iTop = y - textHeight;
+ screenint iTop = y - textDims.second;
if (y>=0) {
- Screen()->DrawString(pText->m_String, x-textWidth/2, y-textHeight, pText->m_iSize, pText->m_iColor);
+ Screen()->DrawString(pText->m_pLabel, x-textDims.first/2, iTop, pText->m_iSize, pText->m_iColor);
for (vector<CTextString *>::iterator it = pText->m_children.begin(); it!=pText->m_children.end(); it++) {
CTextString *pChild=*it;
pChild->m_iy = min(pChild->m_iy, iTop);
@@ -483,13 +483,12 @@ void CDasherViewSquare::DisjointRender(CDasherNode *pRender, myint y1, myint y2,
const int myColor = pRender->getColour();
- const std::string &sDisplayText(pRender->getDisplayText());
- if( sDisplayText.size() > 0 )
+ if( pRender->getLabel() )
{
const int textColor = GetLongParameter(LP_OUTLINE_WIDTH)<0 ? myColor : 4;
myint ny1 = std::min(iDasherMaxY, std::max(iDasherMinY, y1)),
ny2 = std::min(iDasherMaxY, std::max(iDasherMinY, y2));
- CTextString *pText = DasherDrawText(y2-y1, (ny1+ny2)/2, sDisplayText, pPrevText, textColor);
+ CTextString *pText = DasherDrawText(y2-y1, (ny1+ny2)/2, pRender->getLabel(), pPrevText, textColor);
if (pRender->bShove()) pPrevText = pText;
}
@@ -657,13 +656,12 @@ beginning:
const int myColor = pRender->getColour();
- const std::string &sDisplayText(pRender->getDisplayText());
- if( sDisplayText.size() > 0 )
+ if( pRender->getLabel() )
{
const int textColor = GetLongParameter(LP_OUTLINE_WIDTH)<0 ? myColor : 4;
myint ny1 = std::min(iDasherMaxY, std::max(iDasherMinY, y1)),
ny2 = std::min(iDasherMaxY, std::max(iDasherMinY, y2));
- CTextString *pText = DasherDrawText(y2-y1, (ny1+ny2)/2, sDisplayText, pPrevText, textColor);
+ CTextString *pText = DasherDrawText(y2-y1, (ny1+ny2)/2, pRender->getLabel(), pPrevText, textColor);
if (pRender->bShove()) pPrevText = pText;
}
@@ -1129,8 +1127,7 @@ void CDasherViewSquare::VisibleRegion( myint &iDasherMinX, myint &iDasherMinY, m
// Screen()->Polyline(p, 4, iWidth, iColour);
// }
-void CDasherViewSquare::ChangeScreen(CDasherScreen *NewScreen) {
- CDasherView::ChangeScreen(NewScreen);
+void CDasherViewSquare::ScreenResized(CDasherScreen *NewScreen) {
m_bVisibleRegionValid = false;
m_iScalingFactor = 100000000;
SetScaleFactor();
diff --git a/Src/DasherCore/DasherViewSquare.h b/Src/DasherCore/DasherViewSquare.h
index 30216a8..db8f693 100644
--- a/Src/DasherCore/DasherViewSquare.h
+++ b/Src/DasherCore/DasherViewSquare.h
@@ -56,11 +56,8 @@ public:
virtual void HandleEvent(Dasher::CEvent * pEvent);
- ///
- /// Supply a new screen to draw to
- ///
-
- void ChangeScreen(CDasherScreen * NewScreen);
+ /// Resets scale factors etc. that depend on the screen size, to be recomputed when next needed.
+ void ScreenResized(CDasherScreen * NewScreen);
///
/// @name Coordinate system conversion
@@ -116,14 +113,14 @@ private:
class CTextString {
public: //to CDasherViewSquare...
- ///Creates a request that string str will be drawn.
+ ///Creates a request that label will be drawn.
/// x,y are screen coords of midpoint of leading edge;
/// iSize is desired size (already computed from requested position)
- CTextString(const std::string & str, screenint x, screenint y, int iSize, int iColor)
- : m_String(str), m_ix(x), m_iy(y), m_iSize(iSize), m_iColor(iColor) {
+ CTextString(CDasherScreen::Label *pLabel, screenint x, screenint y, int iSize, int iColor)
+ : m_pLabel(pLabel), m_ix(x), m_iy(y), m_iSize(iSize), m_iColor(iColor) {
}
~CTextString();
- std::string m_String;
+ CDasherScreen::Label *m_pLabel;
screenint m_ix,m_iy;
vector<CTextString *> m_children;
int m_iSize;
@@ -137,7 +134,7 @@ private:
/// Draw text specified in Dasher co-ordinates
///
- CTextString *DasherDrawText(myint iMaxX, myint iMidY, const std::string & sDisplayText, CTextString *pParent, int iColor);
+ CTextString *DasherDrawText(myint iMaxX, myint iMidY, CDasherScreen::Label *pLabel, CTextString *pParent, int iColor);
///
/// (Recursively) render a node and all contained subnodes, in disjoint rects.
diff --git a/Src/DasherCore/MandarinAlphMgr.cpp b/Src/DasherCore/MandarinAlphMgr.cpp
index 0052da7..0539d8b 100644
--- a/Src/DasherCore/MandarinAlphMgr.cpp
+++ b/Src/DasherCore/MandarinAlphMgr.cpp
@@ -63,10 +63,10 @@ CMandarinAlphMgr::CMandarinAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreati
if (symbol para = pCHAlphabet->GetParagraphSymbol())
conversions[pCHAlphabet->GetDisplayText(para)]=pair<symbol,symbol>(para,para+1);
//Non-recursive traversal of all the groups in the CHAlphabet (we don't care where they are, just to find them)
- vector<const SGroupInfo *> groups;
+ vector<const ::SGroupInfo *> groups;
groups.push_back(pCHAlphabet->m_pBaseGroup);
while (!groups.empty()) {
- const SGroupInfo *pGroup(groups.back()); groups.pop_back();
+ const ::SGroupInfo *pGroup(groups.back()); groups.pop_back();
if (pGroup->pNext) groups.push_back(pGroup->pNext);
if (pGroup->pChild) groups.push_back(pGroup->pChild);
//process this group. The SPY syll+tone is stored as the label, using a tone mark over the vowel, e.g. ā = a1
@@ -112,6 +112,16 @@ CMandarinAlphMgr::CMandarinAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreati
//that leaves m_pConversionsBySymbol as desired.
}
+void CMandarinAlphMgr::MakeLabels(CDasherScreen *pScreen) {
+ CAlphabetManager::MakeLabels(pScreen);
+ //a bit of a waste, that fills m_vLabels with labels for all the pinyin symbols - which we don't use.
+ for (vector<CDasherScreen::Label *>::iterator it=m_vLabels.begin(); it!=m_vLabels.end(); it++)
+ delete *it;
+ m_vLabels.clear();
+ //instead, keep the screen to create labels lazily...
+ m_pScreen = pScreen;
+}
+
CMandarinAlphMgr::~CMandarinAlphMgr() {
delete[] m_pConversionsBySymbol;
}
@@ -137,10 +147,10 @@ CAlphabetManager::CAlphNode *CMandarinAlphMgr::GetRoot(CDasherNode *pParent, uns
CAlphNode *pNewNode;
if (p.first==0 || !bEnteredLast) {
- pNewNode = new CGroupNode(pParent, iNewOffset, iLower, iUpper, "", 0, this, NULL);
+ pNewNode = new CGroupNode(pParent, iNewOffset, iLower, iUpper, NULL, 0, this, NULL);
} else {
DASHER_ASSERT(p.first>0 && p.first<m_CHtext.size());
- pNewNode = new CMandSym(pParent, iNewOffset, iLower, iUpper, "", this, p.first, 0);
+ pNewNode = new CMandSym(pParent, iNewOffset, iLower, iUpper, this, p.first, 0);
}
pNewNode->iContext = p.second;
@@ -165,7 +175,7 @@ int CMandarinAlphMgr::GetCHColour(symbol CHsym, int iOffset) const {
return iColour;
}
-CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
+CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol) {
//For every PY symbol (=syllable+tone, or "punctuation"),
// m_pConversionsBySymbol identifies the possible chinese-alphabet symbols
@@ -173,24 +183,24 @@ CDasherNode *CMandarinAlphMgr::CreateSymbolNode(CAlphNode *pParent, unsigned int
// punctuation character in the chinese alphabet). A CConvRoot thus offers a choice between them...
if (m_pConversionsBySymbol[iSymbol].size()>1)
- return CreateConvRoot(pParent, iLbnd, iHbnd, strGroup, iSymbol);
+ return CreateConvRoot(pParent, iLbnd, iHbnd, iSymbol);
- return CreateCHSymbol(pParent,pParent->iContext, iLbnd, iHbnd, strGroup, *(m_pConversionsBySymbol[iSymbol].begin()), iSymbol);
+ return CreateCHSymbol(pParent,pParent->iContext, iLbnd, iHbnd, *(m_pConversionsBySymbol[iSymbol].begin()), iSymbol);
}
-CMandarinAlphMgr::CConvRoot *CMandarinAlphMgr::CreateConvRoot(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iPYsym) {
+CMandarinAlphMgr::CConvRoot *CMandarinAlphMgr::CreateConvRoot(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iPYsym) {
// the same offset as we've still not entered/selected a symbol (leaf);
// Colour is always 9 so ignore iBkgCol
- CConvRoot *pConv = new CConvRoot(pParent, pParent->offset(), iLbnd, iHbnd, strGroup, this, iPYsym);
+ CConvRoot *pConv = new CConvRoot(pParent, pParent->offset(), iLbnd, iHbnd, this, iPYsym);
// and use the same context too (pinyin syll+tone is _not_ used as part of the LM context)
pConv->iContext = m_pLanguageModel->CloneContext(pParent->iContext);
return pConv;
}
-CMandarinAlphMgr::CConvRoot::CConvRoot(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol pySym)
-: CAlphBase(pParent, iOffset, iLbnd, iHbnd, 9, strGroup, pMgr), m_pySym(pySym) {
+CMandarinAlphMgr::CConvRoot::CConvRoot(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CMandarinAlphMgr *pMgr, symbol pySym)
+: CAlphBase(pParent, iOffset, iLbnd, iHbnd, 9, NULL, pMgr), m_pySym(pySym) {
DASHER_ASSERT(pMgr->m_pConversionsBySymbol[pySym].size()>1);
//colour + label from ConversionManager.
}
@@ -218,31 +228,31 @@ void CMandarinAlphMgr::CConvRoot::PopulateChildrenWithExisting(CMandSym *existin
iCum = iHbnd;
CMandSym *pNewNode = (existing)
? existing->RebuildCHSymbol(this, iLbnd, iHbnd, it->first)
- : mgr()->CreateCHSymbol(this, this->iContext, iLbnd, iHbnd, "", it->first, m_pySym);
+ : mgr()->CreateCHSymbol(this, this->iContext, iLbnd, iHbnd, it->first, m_pySym);
DASHER_ASSERT(GetChildren().back()==pNewNode);
}
}
-CMandarinAlphMgr::CMandSym *CMandarinAlphMgr::CreateCHSymbol(CDasherNode *pParent, CLanguageModel::Context iContext, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iCHsym, symbol iPYparent) {
+CMandarinAlphMgr::CMandSym *CMandarinAlphMgr::CreateCHSymbol(CDasherNode *pParent, CLanguageModel::Context iContext, unsigned int iLbnd, unsigned int iHbnd, symbol iCHsym, symbol iPYparent) {
// TODO: Parameters here are placeholders - need to figure out
// what's right
int iNewOffset = pParent->offset()+1;
if (m_CHtext[iCHsym] == "\r\n") iNewOffset++;
- CMandSym *pNewNode = new CMandSym(pParent, iNewOffset, iLbnd, iHbnd, strGroup, this, iCHsym, iPYparent);
+ CMandSym *pNewNode = new CMandSym(pParent, iNewOffset, iLbnd, iHbnd, this, iCHsym, iPYparent);
pNewNode->iContext = m_pLanguageModel->CloneContext(iContext);
m_pLanguageModel->EnterSymbol(pNewNode->iContext, iCHsym);
return pNewNode;
}
-CDasherNode *CMandarinAlphMgr::CConvRoot::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSym) {
+CDasherNode *CMandarinAlphMgr::CConvRoot::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSym) {
if (iSym == m_pySym) {
SetParent(pParent);
SetRange(iLbnd,iHbnd);
return this;
}
- return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSym);
+ return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, iSym);
}
bool CMandarinAlphMgr::CConvRoot::isInGroup(const SGroupInfo *pGroup) {
@@ -337,11 +347,21 @@ void CMandarinAlphMgr::GetConversions(std::vector<pair<symbol,unsigned int> > &v
}
-CMandarinAlphMgr::CMandSym::CMandSym(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol iSymbol, symbol pyParent)
-: CSymbolNode(pParent, iOffset, iLbnd, iHbnd, pMgr->GetCHColour(iSymbol,iOffset), strGroup+pMgr->m_CHdisplayText[iSymbol], pMgr, iSymbol), m_pyParent(pyParent) {
+CDasherScreen::Label *CMandarinAlphMgr::GetLabel(int iCHsym) {
+ //TODO: LRU cache, keep down to some sensible #labels allocated?
+ if (iCHsym>=m_vLabels.size()) {
+ m_vLabels.resize(iCHsym+1);
+ } else if (m_vLabels[iCHsym]) {
+ return m_vLabels[iCHsym];
+ }
+ return m_vLabels[iCHsym] = m_pScreen->MakeLabel(m_CHdisplayText[iCHsym]);
+}
+
+CMandarinAlphMgr::CMandSym::CMandSym(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CMandarinAlphMgr *pMgr, symbol iSymbol, symbol pyParent)
+: CSymbolNode(pParent, iOffset, iLbnd, iHbnd, pMgr->GetCHColour(iSymbol,iOffset), pMgr->GetLabel(iSymbol), pMgr, iSymbol), m_pyParent(pyParent) {
}
-CDasherNode *CMandarinAlphMgr::CMandSym::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol) {
+CDasherNode *CMandarinAlphMgr::CMandSym::RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol) {
DASHER_ASSERT(m_pyParent!=0); //should have been computed in RebuildForwardsFromAncestor()
if (iSymbol==m_pyParent) {
//create the PY node that lead to this chinese
@@ -352,11 +372,11 @@ CDasherNode *CMandarinAlphMgr::CMandSym::RebuildSymbol(CAlphNode *pParent, unsig
return this;
}
//ok, will be a PY-to-Chinese conversion choice
- CConvRoot *pConv = mgr()->CreateConvRoot(pParent, iLbnd, iHbnd, strGroup, iSymbol);
+ CConvRoot *pConv = mgr()->CreateConvRoot(pParent, iLbnd, iHbnd, iSymbol);
pConv->PopulateChildrenWithExisting(this);
return pConv;
}
- return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, strGroup, iBkgCol, iSymbol);
+ return CAlphBase::RebuildSymbol(pParent, iLbnd, iHbnd, iSymbol);
}
bool CMandarinAlphMgr::CMandSym::isInGroup(const SGroupInfo *pGroup) {
@@ -372,7 +392,7 @@ CMandarinAlphMgr::CMandSym *CMandarinAlphMgr::CMandSym::RebuildCHSymbol(CConvRoo
SetRange(iLbnd, iHbnd);
return this;
}
- return mgr()->CreateCHSymbol(pParent, pParent->iContext, iLbnd, iHbnd, "", iNewSym, pParent->m_pySym);
+ return mgr()->CreateCHSymbol(pParent, pParent->iContext, iLbnd, iHbnd, iNewSym, pParent->m_pySym);
}
void CMandarinAlphMgr::CMandSym::RebuildForwardsFromAncestor(CAlphNode *pNewNode) {
diff --git a/Src/DasherCore/MandarinAlphMgr.h b/Src/DasherCore/MandarinAlphMgr.h
index b2264d3..5602743 100644
--- a/Src/DasherCore/MandarinAlphMgr.h
+++ b/Src/DasherCore/MandarinAlphMgr.h
@@ -79,6 +79,7 @@ namespace Dasher {
CAlphNode *GetRoot(CDasherNode *pParent, unsigned int iLower, unsigned int iUpper, bool bEnteredLast, int iOffset);
protected:
+ void MakeLabels(CDasherScreen *pScreen);
class CConvRoot;
///Subclass of CSymbolNode for (converted) chinese-alphabet symbols:
/// these use the chinese alphabet in place of the pinyin one for text to display/enter,
@@ -87,9 +88,8 @@ namespace Dasher {
public:
CMandarinAlphMgr *mgr() {return static_cast<CMandarinAlphMgr *>(CSymbolNode::mgr());}
///Symbol constructor: display text from CHAlphabet, colour from GetCHColour
- /// \param strGroup caption of any group(s) containing this symbol for which no nodes created; prepended to display text.
- CMandSym(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol iSymbol, symbol pyParent);
- CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+ CMandSym(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CMandarinAlphMgr *pMgr, symbol iSymbol, symbol pyParent);
+ CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol);
CMandSym *RebuildCHSymbol(CConvRoot *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iNewSym);
protected:
///Override to compute which pinyin symbol to make our parent...
@@ -109,7 +109,7 @@ namespace Dasher {
class CConvRoot : public CAlphBase {
public:
/// \param pySym symbol in pinyin alphabet; must have >1 possible chinese conversion.
- CConvRoot(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, CMandarinAlphMgr *pMgr, symbol pySym);
+ CConvRoot(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, CMandarinAlphMgr *pMgr, symbol pySym);
CMandarinAlphMgr *mgr() {return static_cast<CMandarinAlphMgr *>(CAlphBase::mgr());}
void PopulateChildren();
void PopulateChildrenWithExisting(CMandSym *existing);
@@ -117,7 +117,7 @@ namespace Dasher {
CLanguageModel::Context iContext;
void SetFlag(int iFlag, bool bValue);
const symbol m_pySym;
- CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+ CDasherNode *RebuildSymbol(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol);
protected:
bool isInGroup(const SGroupInfo *pGroup);
private:
@@ -126,23 +126,22 @@ namespace Dasher {
///Called to create the node for a pinyin leaf symbol;
/// Overridden to call either CreateConvRoot or CreateCHSymbol, according to #chinese symbols under specified pinyin
/// \param iSymbol Symbol number in pinyin alphabet
- virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, int iBkgCol, symbol iSymbol);
+ virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iSymbol);
///Creates a CConvRoot, for a Pinyin symbol with multiple possible chinese symbols.
/// Colour is always 9 (opaque), so no need for background colour.
/// \param pParent parent node, context will be taken from here
/// \param iPYsym Symbol (leaf) in pinyin alphabet
- CConvRoot *CreateConvRoot(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iPYsym);
+ CConvRoot *CreateConvRoot(CAlphNode *pParent, unsigned int iLbnd, unsigned int iHbnd, symbol iPYsym);
///Creates a node for (i.e. that will actually enter) a chinese symbol
/// \param pParent parent node: could be a CGroupNode (directly), if some pinyin symbol in that group had only
/// one corresponding chinese symbol (=> this), or a CConvRoot (if this chinese symbol is one of many possible
/// chinese symbols for a particular pinyin).
/// \param iContext parent node's context, from which to generate context for this node
- /// \param strGroup caption of any elided groups (prepended to this node's caption)
/// \param iCHsym symbol number in chinese alphabet
/// \param pyParent pinyin-alphabet symbol which was used to enter this chinese symbol (if known, else 0)
- CMandSym *CreateCHSymbol(CDasherNode *pParent, CLanguageModel::Context iContext, unsigned int iLbnd, unsigned int iHbnd, const std::string &strGroup, symbol iCHsym, symbol pyParent);
+ CMandSym *CreateCHSymbol(CDasherNode *pParent, CLanguageModel::Context iContext, unsigned int iLbnd, unsigned int iHbnd, symbol iCHsym, symbol pyParent);
///Gets the possible chinese symbols for a pinyin one, along with their probabilities in the specified context.
///Probabilities are computed by CPPMPYLanguageModel::GetPartProbs, then renormalized here. (TODO unnecessary?)
@@ -175,6 +174,10 @@ namespace Dasher {
/// returned by CAlphabetMap::GetSymbols() for that text)
/// the set of pinyin syllable+tones which could yield that symbol.
std::map<symbol,std::set<symbol> > m_PinyinByChinese;
+
+ //Used to create labels lazily
+ CDasherScreen *m_pScreen;
+ CDasherScreen::Label *GetLabel(int iCHsym);
};
/// @}
diff --git a/Src/DasherCore/NodeCreationManager.cpp b/Src/DasherCore/NodeCreationManager.cpp
index 00187af..9efeb9f 100644
--- a/Src/DasherCore/NodeCreationManager.cpp
+++ b/Src/DasherCore/NodeCreationManager.cpp
@@ -12,7 +12,7 @@ CNodeCreationManager::CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterf
Dasher::CEventHandler *pEventHandler,
CSettingsStore *pSettingsStore,
Dasher::CAlphIO *pAlphIO) : CDasherComponent(pEventHandler, pSettingsStore),
- m_pInterface(pInterface), m_pControlManager(NULL) {
+ m_pInterface(pInterface), m_pControlManager(NULL), m_pScreen(NULL) {
const Dasher::CAlphInfo *pAlphInfo(pAlphIO->GetInfo(pSettingsStore->GetStringParameter(SP_ALPHABET_ID)));
const CAlphabetMap *pAlphMap = pAlphInfo->MakeMap();
@@ -98,6 +98,13 @@ CNodeCreationManager::~CNodeCreationManager() {
delete m_pControlManager;
}
+void CNodeCreationManager::ChangeScreen(CDasherScreen *pScreen) {
+ if (m_pScreen == pScreen) return;
+ m_pScreen = pScreen;
+ m_pAlphabetManager->MakeLabels(pScreen);
+ if (m_pControlManager) m_pControlManager->MakeLabels(pScreen);
+}
+
void CNodeCreationManager::HandleEvent(CEvent *pEvent) {
if (pEvent->m_iEventType == EV_PARAM_NOTIFY) {
switch (static_cast<CParameterNotificationEvent *>(pEvent)->m_iParameter) {
@@ -107,6 +114,7 @@ void CNodeCreationManager::HandleEvent(CEvent *pEvent) {
unsigned long iControlSpace;
if (GetBoolParameter(BP_CONTROL_MODE)) {
m_pControlManager = new CControlManager(m_pEventHandler, m_pSettingsStore, this, m_pInterface);
+ if (m_pScreen) m_pControlManager->MakeLabels(m_pScreen);
iControlSpace = iNorm / 20;
} else {
m_pControlManager = NULL;
diff --git a/Src/DasherCore/NodeCreationManager.h b/Src/DasherCore/NodeCreationManager.h
index 68213c6..b2ed99e 100644
--- a/Src/DasherCore/NodeCreationManager.h
+++ b/Src/DasherCore/NodeCreationManager.h
@@ -18,6 +18,7 @@ namespace Dasher {
class CDasherNode;
class CDasherInterfaceBase;
class CControlManager;
+ class CDasherScreen;
}
//TODO why is CNodeCreationManager _not_ in namespace Dasher?!?!
/// \ingroup Model
@@ -30,6 +31,9 @@ class CNodeCreationManager : public Dasher::CDasherComponent {
Dasher::CAlphIO *pAlphIO);
~CNodeCreationManager();
+ ///Tells us the screen on which all created node labels must be rendered
+ void ChangeScreen(Dasher::CDasherScreen *pScreen);
+
//we watch for changes to BP_CONTROL_MODE and create the Control Manager lazily
void HandleEvent(Dasher::CEvent *pEvent);
///
@@ -66,6 +70,9 @@ class CNodeCreationManager : public Dasher::CDasherComponent {
///Amount of probability space to assign to letters (language model + smoothing),
/// i.e. remaining after taking away whatever we need for control mode (perhaps 0)
unsigned long m_iAlphNorm;
+
+ ///Screen to use to create node labels
+ Dasher::CDasherScreen *m_pScreen;
};
/// @}
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 5484b36..303636d 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -30,7 +30,7 @@
// All parameters go into the enums here
// They are unique across the different types
enum {
- BP_MULTISIZE_FONTS, BP_DRAW_MOUSE_LINE, BP_DRAW_MOUSE, BP_CURVE_MOUSE_LINE,
+ BP_DRAW_MOUSE_LINE, BP_DRAW_MOUSE, BP_CURVE_MOUSE_LINE,
BP_SHOW_SLIDER, BP_START_MOUSE,
BP_START_SPACE, BP_STOP_IDLE, BP_CONTROL_MODE,
BP_COLOUR_MODE, BP_MOUSEPOS_MODE,
@@ -124,7 +124,6 @@ struct sp_table {
// The only important thing here is that these are in the same order
// as the enum declarations (could add check in class that enforces this instead)
static bp_table boolparamtable[] = {
- {BP_MULTISIZE_FONTS, "MultiSizeFonts", PERS, false, "Use multiple font sizes"},
{BP_DRAW_MOUSE_LINE, "DrawMouseLine", PERS, true, "Draw Mouse Line"},
{BP_DRAW_MOUSE, "DrawMouse", PERS, false, "Draw Mouse Position"},
{BP_CURVE_MOUSE_LINE, "CurveMouseLine", PERS, false, "Curve mouse line according to screen nonlinearity"},
diff --git a/Src/Gtk2/Canvas.cpp b/Src/Gtk2/Canvas.cpp
index 64fbeec..5fc66f9 100644
--- a/Src/Gtk2/Canvas.cpp
+++ b/Src/Gtk2/Canvas.cpp
@@ -7,9 +7,8 @@
using namespace Dasher;
-CCanvas::CCanvas(GtkWidget *pCanvas, CPangoCache *pPangoCache,
- screenint iWidth, screenint iHeight)
- : CDasherScreen(iWidth, iHeight) {
+CCanvas::CCanvas(GtkWidget *pCanvas)
+ : CLabelListScreen(0,0) {
#if WITH_CAIRO
cairo_colours = 0;
@@ -18,24 +17,31 @@ CCanvas::CCanvas(GtkWidget *pCanvas, CPangoCache *pPangoCache,
#endif
m_pCanvas = pCanvas;
- m_pPangoCache = pPangoCache;
-
+
+ gtk_widget_add_events(m_pCanvas, GDK_ALL_EVENTS_MASK);
+
+ InitSurfaces(); //will create 0*0 surfaces. Is that a good idea? It seems to
+ // let us create PangoLayouts ok, which is what we need - but if we can
+ // create them without a backing surface at all, that might be better...
+}
+
+void CCanvas::InitSurfaces() {
// Construct the buffer pixmaps
// FIXME - only allocate without cairo
#if WITH_CAIRO
- m_pDisplaySurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, m_iWidth, m_iHeight);
- m_pDecorationSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, m_iWidth, m_iHeight);
- //m_pOnscreenSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, m_iWidth, m_iHeight);
+ m_pDisplaySurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, GetWidth(), GetHeight());
+ m_pDecorationSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, GetWidth(), GetHeight());
+ //m_pOnscreenSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, GetWidth(), GetHeight());
#else
- //m_pDummyBuffer = gdk_pixmap_new(pCanvas->window, m_iWidth, m_iHeight, -1);
+ //m_pDummyBuffer = gdk_pixmap_new(pCanvas->window, GetWidth(), GetHeight(), -1);
- m_pDisplayBuffer = gdk_pixmap_new(pCanvas->window, m_iWidth, m_iHeight, -1);
- m_pDecorationBuffer = gdk_pixmap_new(pCanvas->window, m_iWidth, m_iHeight, -1);
- //m_pOnscreenBuffer = gdk_pixmap_new(pCanvas->window, m_iWidth, m_iHeight, -1);
+ m_pDisplayBuffer = gdk_pixmap_new(pCanvas->window, GetWidth(), GetHeight(), -1);
+ m_pDecorationBuffer = gdk_pixmap_new(pCanvas->window, GetWidth(), GetHeight(), -1);
+ //m_pOnscreenBuffer = gdk_pixmap_new(pCanvas->window, GetWidth(), GetHeight(), -1);
// Set the display buffer to be current
@@ -60,11 +66,9 @@ CCanvas::CCanvas(GtkWidget *pCanvas, CPangoCache *pPangoCache,
//onscreen_cr = cairo_create(m_pOnscreenSurface);
#endif
-
- gtk_widget_add_events(m_pCanvas, GDK_ALL_EVENTS_MASK);
}
-CCanvas::~CCanvas() {
+void CCanvas::DestroySurfaces() {
// Free the buffer pixmaps
#if WITH_CAIRO
@@ -81,12 +85,21 @@ CCanvas::~CCanvas() {
g_object_unref(m_pDecorationBuffer);
//g_object_unref(m_pOnscreenBuffer);
#endif
+}
+CCanvas::~CCanvas() {
+ DestroySurfaces();
#if WITH_CAIRO
delete[] cairo_colours;
#endif
}
+void CCanvas::resize(screenint w,screenint h) {
+ DestroySurfaces();
+ CDasherScreen::resize(w,h);
+ InitSurfaces();
+}
+
void CCanvas::Blank() {
// FIXME - this is replicated throughout this file - do something
// about that
@@ -105,7 +118,7 @@ void CCanvas::Blank() {
#if WITH_CAIRO
cairo_paint(cr);
#else
- gdk_draw_rectangle(m_pOffscreenBuffer, graphics_context, TRUE, 0, 0, m_iWidth, m_iHeight);
+ gdk_draw_rectangle(m_pOffscreenBuffer, graphics_context, TRUE, 0, 0, GetWidth(), GetHeight());
#endif
END_DRAWING;
@@ -131,12 +144,12 @@ void CCanvas::Display() {
// TODO: Reimplement (kind of important!)
- // gdk_draw_drawable(m_pOnscreenBuffer, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pOffscreenBuffer, 0, 0, 0, 0, m_iWidth, m_iHeight);
+ // gdk_draw_drawable(m_pOnscreenBuffer, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pOffscreenBuffer, 0, 0, 0, 0, GetWidth(), GetHeight());
// BEGIN_DRAWING;
// cairo_set_source_surface(onscreen_cr, m_pDecorationSurface, 0, 0);
-// cairo_rectangle(onscreen_cr, 0, 0, m_iWidth, m_iHeight);
+// cairo_rectangle(onscreen_cr, 0, 0, GetWidth(), GetHeight());
// cairo_fill(onscreen_cr);
@@ -145,20 +158,20 @@ void CCanvas::Display() {
// Blank the offscreen buffer (?)
- // gdk_draw_rectangle(m_pOffscreenBuffer, graphics_context, TRUE, 0, 0, m_iWidth, m_iHeight);
+ // gdk_draw_rectangle(m_pOffscreenBuffer, graphics_context, TRUE, 0, 0, GetWidth(), GetHeight());
// Invalidate the full canvas to force it to be redrawn on-screen
// update_rect.x = 0;
// update_rect.y = 0;
-// update_rect.width = m_iWidth;
-// update_rect.height = m_iHeight;
+// update_rect.width = GetWidth();
+// update_rect.height = GetHeight();
// gdk_window_invalidate_rect(m_pCanvas->window, &update_rect, FALSE);
// BEGIN_DRAWING;
- // GdkRectangle sRect = {0, 0, m_iWidth, m_iHeight};
+ // GdkRectangle sRect = {0, 0, GetWidth(), GetHeight()};
// gdk_window_begin_paint_rect(m_pCanvas->window, &sRect);
#if WITH_CAIRO
@@ -169,11 +182,11 @@ void CCanvas::Display() {
widget_cr = gdk_cairo_create(m_pCanvas->window);
#endif
cairo_set_source_surface(widget_cr, m_pDecorationSurface, 0, 0);
- cairo_rectangle(widget_cr, 0, 0, m_iWidth, m_iHeight);
+ cairo_rectangle(widget_cr, 0, 0, GetWidth(), GetHeight());
cairo_fill(widget_cr);
cairo_destroy(widget_cr);
#else
- gdk_draw_drawable(m_pCanvas->window, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pDecorationBuffer, 0, 0, 0, 0, m_iWidth, m_iHeight);
+ gdk_draw_drawable(m_pCanvas->window, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pDecorationBuffer, 0, 0, 0, 0, GetWidth(), GetHeight());
#endif
// gdk_window_end_paint(m_pCanvas->window);
@@ -399,7 +412,56 @@ void CCanvas::Polyline(Dasher::CDasherScreen::point *Points, int Number, int iWi
END_DRAWING;
}
-void CCanvas::DrawString(const std::string &String, screenint x1, screenint y1, int size, int iColor) {
+CDasherScreen::Label *CCanvas::MakeLabel(const string &strText) {
+ return new CPangoLabel(this, strText);
+}
+
+void CCanvas::SetFont(const std::string &strName) {
+ m_strFontName=strName;
+ for (map<unsigned int,PangoFontDescription *>::iterator it=m_mFonts.begin(); it!=m_mFonts.end(); it++) {
+ pango_font_description_free(it->second);
+ it->second = pango_font_description_from_string(m_strFontName.c_str());
+ pango_font_description_set_size(it->second,it->first);
+ }
+ for (set<CLabelListScreen::Label *>::iterator it=LabelsBegin(); it!=LabelsEnd(); it++) {
+ map<unsigned int,PangoLayout *> &layouts(static_cast<CPangoLabel *>(*it)->m_mLayouts);
+ for (map<unsigned int,PangoLayout *>::iterator it2=layouts.begin(); it2!=layouts.end(); it2++) {
+ DASHER_ASSERT(m_mFonts.find(it2->first) != m_mFonts.end()); //central font repository knows about this size
+ pango_layout_set_font_description(it2->second,m_mFonts[it2->first]);
+ }
+ }
+}
+
+PangoLayout *CCanvas::GetLayout(CPangoLabel *label, unsigned int iFontSize) {
+ {
+ map<unsigned int,PangoLayout *>::iterator it = label->m_mLayouts.find(iFontSize);
+ if (it != label->m_mLayouts.end()) return it->second;
+ }
+#if WITH_CAIRO
+ PangoLayout *pNewPangoLayout(pango_cairo_create_layout(cr));
+#else
+ PangoLayout *pNewPangoLayout(gtk_widget_create_pango_layout(pCanvas, ""));
+#endif
+ label->m_mLayouts.insert(pair<unsigned int,PangoLayout *>(iFontSize, pNewPangoLayout));
+
+ pango_layout_set_text(pNewPangoLayout, label->m_strText.c_str(), -1);
+
+ PangoFontDescription *pF;
+ {
+ map<unsigned int,PangoFontDescription *>::iterator it = m_mFonts.find(iFontSize);
+ if (it != m_mFonts.end())
+ pF=it->second;
+ else {
+ pF = pango_font_description_from_string(m_strFontName.c_str());
+ pango_font_description_set_size(pF, iFontSize * PANGO_SCALE);
+ m_mFonts[iFontSize] = pF;
+ }
+ pango_layout_set_font_description(pNewPangoLayout, pF);
+ }
+ return pNewPangoLayout;
+}
+
+void CCanvas::DrawString(CDasherScreen::Label *label, screenint x1, screenint y1, unsigned int size, int iColor) {
#if WITH_CAIRO
#else
@@ -413,11 +475,7 @@ void CCanvas::DrawString(const std::string &String, screenint x1, screenint y1,
BEGIN_DRAWING;
SET_COLOR(iColor);
-#if WITH_CAIRO
- PangoLayout *pLayout(m_pPangoCache->GetLayout(cr, String, size));
-#else
- PangoLayout *pLayout(m_pPangoCache->GetLayout(GTK_WIDGET(m_pCanvas), String, size));
-#endif
+ PangoLayout *pLayout(GetLayout(static_cast<CPangoLabel*>(label),size));
PangoRectangle sPangoInk;
@@ -434,18 +492,13 @@ void CCanvas::DrawString(const std::string &String, screenint x1, screenint y1,
END_DRAWING;
}
-void CCanvas::TextSize(const std::string &String, screenint *Width, screenint *Height, int size) {
-#if WITH_CAIRO
- PangoLayout *pLayout(m_pPangoCache->GetLayout(cr, String, size));
-#else
- PangoLayout *pLayout(m_pPangoCache->GetLayout(GTK_WIDGET(m_pCanvas), String, size));
-#endif
+pair<screenint,screenint> CCanvas::TextSize(CDasherScreen::Label *label, unsigned int size) {
+ PangoLayout *pLayout(GetLayout(static_cast<CPangoLabel*>(label),size));
PangoRectangle sPangoInk;
pango_layout_get_pixel_extents(pLayout, &sPangoInk, NULL);
- *Width = sPangoInk.width;
- *Height = sPangoInk.height;
+ return pair<screenint,screenint>(sPangoInk.width,sPangoInk.height);
}
void CCanvas::SendMarker(int iMarker) {
@@ -462,11 +515,11 @@ void CCanvas::SendMarker(int iMarker) {
#if WITH_CAIRO
cairo_set_source_surface(decoration_cr, m_pDisplaySurface, 0, 0);
- cairo_rectangle(decoration_cr, 0, 0, m_iWidth, m_iHeight);
+ cairo_rectangle(decoration_cr, 0, 0, GetWidth(), GetHeight());
cairo_fill(decoration_cr);
cr = decoration_cr;
#else
- gdk_draw_drawable(m_pDecorationBuffer, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pDisplayBuffer, 0, 0, 0, 0, m_iWidth, m_iHeight);
+ gdk_draw_drawable(m_pDecorationBuffer, m_pCanvas->style->fg_gc[GTK_WIDGET_STATE(m_pCanvas)], m_pDisplayBuffer, 0, 0, 0, 0, GetWidth(), GetHeight());
m_pOffscreenBuffer = m_pDecorationBuffer;
#endif
break;
@@ -521,8 +574,8 @@ bool CCanvas::GetCanvasSize(GdkRectangle *pRectangle)
pRectangle->x = iX;
pRectangle->y = iY;
- pRectangle->width = m_iWidth;
- pRectangle->height = m_iHeight;
+ pRectangle->width = GetWidth();
+ pRectangle->height = GetHeight();
return true;
}
diff --git a/Src/Gtk2/Canvas.h b/Src/Gtk2/Canvas.h
index 0d9f78d..44987a4 100644
--- a/Src/Gtk2/Canvas.h
+++ b/Src/Gtk2/Canvas.h
@@ -8,7 +8,8 @@
#include <gtk/gtk.h>
#include <gdk/gdk.h>
-#include "PangoCache.h"
+#include <pango/pango.h>
+#include <map>
#include <iostream>
@@ -52,8 +53,6 @@
#define SET_COLOR(c) \
SET_COLOR_BACKEND(c)
-using namespace Dasher;
-
/// CCanvas
///
/// Method definitions for CCanvas, implementing the CDasherScreen
@@ -62,17 +61,16 @@ using namespace Dasher;
/// primitive' should really not be here - higher level drawing
/// functions belong in CDasherView.
-class CCanvas:public Dasher::CDasherScreen {
+class CCanvas:public Dasher::CLabelListScreen {
public:
-
- ///
+ typedef Dasher::screenint screenint;
+ /// Creates a new canvas - initially of zero size, so drawing
+ /// operations won't do anything until a call to resize() is made.
/// \param pCanvas The GTK drawing area used by the canvas
- /// \param pPangoCache A cache for precomputed Pango layouts
///
- CCanvas(GtkWidget *pCanvas, CPangoCache *pPangoCache,
- screenint iWidth, screenint iHeight);
+ CCanvas(GtkWidget *pCanvas);
~CCanvas();
///
@@ -91,28 +89,10 @@ public:
/// \deprecated In Linux - now handled by the pango cache, but need to think how this fits in with Windows
///
- void SetFont(std::string Name) {
- };
-
- ///
- /// Set the font size for rendering
- /// \param fontsize The font size to use
- /// \deprecated Obsolete
- ///
+ void SetFont(const std::string &strName);
- void SetFontSize(Dasher::Opts::FontSize fontsize) {
-
- };
-
- ///
- /// Get the current font size
- /// \deprecated To be removed before 4.0 release
- /// \todo We should not be relying on locally cached variables - check to see whether this is still used or not
- ///
-
- Dasher::Opts::FontSize GetFontSize() {
- return Dasher::Opts::FontSize(1);
- };
+ ///Make a label for use with this screen; caches Pango layout information inside it.
+ CDasherScreen::Label *MakeLabel(const std::string &strText);
///
/// Return the physical extent of a given string being rendered at a given size.
@@ -122,7 +102,7 @@ public:
/// \param Size Size at which the string will be rendered (units?)
///
- void TextSize(const std::string &String, screenint *Width, screenint *Height, int Size);
+ std::pair<screenint,screenint> TextSize(CDasherScreen::Label *label, unsigned int Size);
///
/// Draw a text string
@@ -132,7 +112,7 @@ public:
/// \param Size The size at which to render the rectangle (units?)
///
- void DrawString(const std::string &String, screenint x1, screenint y1, int Size, int iColor);
+ void DrawString(CDasherScreen::Label *label, screenint x1, screenint y1, unsigned int Size, int iColor);
///
/// Draw a rectangle
@@ -196,13 +176,16 @@ public:
/// \param Colours New colours to use
///
- void SetColourScheme(const CColourIO::ColourInfo *pColourScheme);
+ void SetColourScheme(const Dasher::CColourIO::ColourInfo *pColourScheme);
///
/// Gets the location and size of our canvas.
/// Returns true on success, false otherwise.
bool GetCanvasSize(GdkRectangle *pRectangle);
+ // Redeclare to make public and adjust cairo/gdk surface sizes
+ void resize(screenint w,screenint h);
+
private:
///
@@ -211,6 +194,8 @@ private:
GtkWidget *m_pCanvas;
+ void InitSurfaces();
+ void DestroySurfaces();
#if WITH_CAIRO
cairo_surface_t *m_pDisplaySurface;
@@ -250,12 +235,18 @@ private:
#endif
- ///
- /// The Pango cache - used to store pre-computed pango layouts as
- /// they are costly to regenerate every time they are needed.
- ///
+ std::string m_strFontName;
+ std::map<unsigned int,PangoFontDescription *> m_mFonts;
+
+ class CPangoLabel : public CLabelListScreen::Label {
+ public:
+ CPangoLabel(CCanvas *pCanvas, const std::string &strText)
+ : CLabelListScreen::Label(pCanvas, strText) {
+ }
+ std::map<unsigned int,PangoLayout *> m_mLayouts;
+ };
- CPangoCache *m_pPangoCache;
+ PangoLayout *GetLayout(CPangoLabel *label, unsigned int iFontSize);
#if WITH_CAIRO
cairo_t *display_cr;
diff --git a/Src/Gtk2/DasherControl.cpp b/Src/Gtk2/DasherControl.cpp
index f1fba80..3a51857 100644
--- a/Src/Gtk2/DasherControl.cpp
+++ b/Src/Gtk2/DasherControl.cpp
@@ -37,40 +37,11 @@ static bool g_iTimeoutID = 0;
// CDasherControl class definitions
CDasherControl::CDasherControl(GtkVBox *pVBox, GtkDasherControl *pDasherControl) {
- m_pPangoCache = NULL;
m_pScreen = NULL;
m_pDasherControl = pDasherControl;
m_pVBox = GTK_WIDGET(pVBox);
pClipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
- Realize();
-
- // m_pKeyboardHelper = new CKeyboardHelper(this);
- // m_pKeyboardHelper->Grab(GetBoolParameter(BP_GLOBAL_KEYBOARD));
-}
-
-void CDasherControl::CreateModules() {
- CDasherInterfaceBase::CreateModules(); //create default set first
- // Create locally cached copies of the mouse input objects, as we
- // need to pass coordinates to them from the timer callback
- m_pMouseInput =
- (CDasherMouseInput *) RegisterModule(new CDasherMouseInput(m_pEventHandler, m_pSettingsStore));
- SetDefaultInputDevice(m_pMouseInput);
- m_p1DMouseInput =
- (CDasher1DMouseInput *)RegisterModule(new CDasher1DMouseInput(m_pEventHandler, m_pSettingsStore));
- RegisterModule(new CSocketInput(m_pEventHandler, m_pSettingsStore));
-
-#ifdef JOYSTICK
- RegisterModule(new CDasherJoystickInput(m_pEventHandler, m_pSettingsStore, this));
- RegisterModule(new CDasherJoystickInputDiscrete(m_pEventHandler, m_pSettingsStore, this));
-#endif
-
-#ifdef TILT
- RegisterModule(new CDasherTiltInput(m_pEventHandler, m_pSettingsStore, this));
-#endif
-}
-
-void CDasherControl::SetupUI() {
m_pCanvas = gtk_drawing_area_new();
#if GTK_CHECK_VERSION (2,18,0)
gtk_widget_set_can_focus(m_pCanvas, TRUE);
@@ -106,14 +77,42 @@ void CDasherControl::SetupUI() {
g_signal_connect(m_pCanvas, "expose_event", G_CALLBACK(canvas_expose_event), this);
#endif
- // Create the Pango cache
+ m_pScreen = new CCanvas(m_pCanvas);
+ ChangeScreen(m_pScreen);
+
+ Realize();
+
+ // m_pKeyboardHelper = new CKeyboardHelper(this);
+ // m_pKeyboardHelper->Grab(GetBoolParameter(BP_GLOBAL_KEYBOARD));
+}
+
+void CDasherControl::CreateModules() {
+ CDasherInterfaceBase::CreateModules(); //create default set first
+ // Create locally cached copies of the mouse input objects, as we
+ // need to pass coordinates to them from the timer callback
+ m_pMouseInput =
+ (CDasherMouseInput *) RegisterModule(new CDasherMouseInput(m_pEventHandler, m_pSettingsStore));
+ SetDefaultInputDevice(m_pMouseInput);
+ m_p1DMouseInput =
+ (CDasher1DMouseInput *)RegisterModule(new CDasher1DMouseInput(m_pEventHandler, m_pSettingsStore));
+ RegisterModule(new CSocketInput(m_pEventHandler, m_pSettingsStore));
+#ifdef JOYSTICK
+ RegisterModule(new CDasherJoystickInput(m_pEventHandler, m_pSettingsStore, this));
+ RegisterModule(new CDasherJoystickInputDiscrete(m_pEventHandler, m_pSettingsStore, this));
+#endif
+
+#ifdef TILT
+ RegisterModule(new CDasherTiltInput(m_pEventHandler, m_pSettingsStore, this));
+#endif
+}
+
+void CDasherControl::SetupUI() {
// TODO: Use system defaults?
if(GetStringParameter(SP_DASHER_FONT) == "")
SetStringParameter(SP_DASHER_FONT, "Sans 10");
-
- m_pPangoCache = new CPangoCache(GetStringParameter(SP_DASHER_FONT));
-
+ else
+ m_pScreen->SetFont(GetStringParameter(SP_DASHER_FONT));
}
@@ -243,11 +242,6 @@ CDasherControl::~CDasherControl() {
m_p1DMouseInput = NULL;
}
- if(m_pPangoCache) {
- delete m_pPangoCache;
- m_pPangoCache = NULL;
- }
-
// if(m_pKeyboardHelper) {
// delete m_pKeyboardHelper;
// m_pKeyboardHelper = 0;
@@ -333,11 +327,8 @@ int CDasherControl::CanvasConfigureEvent() {
a.height = m_pCanvas->allocation.height;
#endif
- if(m_pScreen != NULL)
- delete m_pScreen;
-
- m_pScreen = new CCanvas(m_pCanvas, m_pPangoCache, a.width, a.height);
- ChangeScreen(m_pScreen);
+ m_pScreen->resize(a.width,a.height);
+ ScreenResized(m_pScreen);
return 0;
}
@@ -435,10 +426,8 @@ void CDasherControl::ExternalKeyUp(int iKeyVal) {
void CDasherControl::HandleParameterNotification(int iParameter) {
switch(iParameter) {
case SP_DASHER_FONT:
- if(m_pPangoCache) {
- m_pPangoCache->ChangeFont(GetStringParameter(SP_DASHER_FONT));
+ m_pScreen->SetFont(GetStringParameter(SP_DASHER_FONT));
ScheduleRedraw();
- }
break;
case BP_GLOBAL_KEYBOARD:
// TODO: reimplement
diff --git a/Src/Gtk2/DasherControl.h b/Src/Gtk2/DasherControl.h
index c2a8ac2..85a2a34 100644
--- a/Src/Gtk2/DasherControl.h
+++ b/Src/Gtk2/DasherControl.h
@@ -5,7 +5,6 @@
#include <config.h>
#endif
-#include "PangoCache.h"
#include "Canvas.h"
#include "../DasherCore/SocketInput.h"
@@ -193,12 +192,6 @@ private:
CDasher1DMouseInput *m_p1DMouseInput;
///
- /// Cache of Pango layouts
- ///
-
- CPangoCache *m_pPangoCache;
-
- ///
/// The CCanvas object
///
diff --git a/Src/Gtk2/Makefile.am b/Src/Gtk2/Makefile.am
index c0d05ad..985180e 100644
--- a/Src/Gtk2/Makefile.am
+++ b/Src/Gtk2/Makefile.am
@@ -35,8 +35,6 @@ libdashercontrol_la_SOURCES = \
GtkDasherControl.h \
KeyboardHelper.cpp \
KeyboardHelper.h \
- PangoCache.cpp \
- PangoCache.h \
Timer.cpp \
Timer.h \
Speech.h \
diff --git a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
index d6efe89..9e34cca 100755
--- a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
+++ b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
@@ -136,22 +136,17 @@
1948BF3A0C226CFD001DFA32 /* UserLogTrial.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE950C226CFD001DFA32 /* UserLogTrial.h */; };
1948BF3E0C226CFD001DFA32 /* XMLUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE9A0C226CFD001DFA32 /* XMLUtil.cpp */; };
1948BF3F0C226CFD001DFA32 /* XMLUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE9B0C226CFD001DFA32 /* XMLUtil.h */; };
- 19558AD60C3182730054A193 /* DasherViewCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 19558AD50C3182730054A193 /* DasherViewCocoa.h */; };
- 196874060C2BDC2E00D63879 /* AlphabetLetter.h in Headers */ = {isa = PBXBuildFile; fileRef = 196874000C2BDC2E00D63879 /* AlphabetLetter.h */; };
- 196874070C2BDC2E00D63879 /* AlphabetLetter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 196874010C2BDC2E00D63879 /* AlphabetLetter.mm */; };
+ 196874060C2BDC2E00D63879 /* OpenGLScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 196874000C2BDC2E00D63879 /* OpenGLScreen.h */; };
+ 196874070C2BDC2E00D63879 /* OpenGLScreen.mm in Sources */ = {isa = PBXBuildFile; fileRef = 196874010C2BDC2E00D63879 /* OpenGLScreen.mm */; };
1968740A0C2BDC2E00D63879 /* GLUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 196874040C2BDC2E00D63879 /* GLUtils.h */; };
1968740B0C2BDC2E00D63879 /* GLUtils.mm in Sources */ = {isa = PBXBuildFile; fileRef = 196874050C2BDC2E00D63879 /* GLUtils.mm */; };
196874290C2BE12E00D63879 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 196874280C2BE12E00D63879 /* OpenGL.framework */; };
1974FE340714861B00B95DA0 /* DasherApp.h in Headers */ = {isa = PBXBuildFile; fileRef = 19C49619045029A40000000A /* DasherApp.h */; };
- 1974FE370714861B00B95DA0 /* ZippyCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 1946CAB90481AD440000000A /* ZippyCache.h */; };
- 1974FE380714861B00B95DA0 /* ZippyString.h in Headers */ = {isa = PBXBuildFile; fileRef = 1946CABB0481AD440000000A /* ZippyString.h */; };
1974FE420714861B00B95DA0 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
1974FE430714861B00B95DA0 /* Preferences.nib in Resources */ = {isa = PBXBuildFile; fileRef = 19D442390454667F0000000A /* Preferences.nib */; };
1974FE440714861B00B95DA0 /* DasherApp.icns in Resources */ = {isa = PBXBuildFile; fileRef = 191CE19C04595BBA0000000A /* DasherApp.icns */; };
1974FE5A0714861B00B95DA0 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = 1974FD9C07145C6500B95DA0 /* Credits.html */; };
1974FE6B0714861B00B95DA0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; };
- 1974FE6F0714861B00B95DA0 /* ZippyCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 1946CABA0481AD440000000A /* ZippyCache.m */; };
- 1974FE700714861B00B95DA0 /* ZippyString.m in Sources */ = {isa = PBXBuildFile; fileRef = 1946CABC0481AD440000000A /* ZippyString.m */; };
1974FE780714861B00B95DA0 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
1988ABBD0C9FF97000D97977 /* GameMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 1988ABB80C9FF97000D97977 /* GameMessages.h */; };
1988ABBE0C9FF97000D97977 /* GameStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = 1988ABB90C9FF97000D97977 /* GameStatistics.h */; };
@@ -317,17 +312,9 @@
19BEF4130C2291CE00275D06 /* colour.vowels2.xml in Resources */ = {isa = PBXBuildFile; fileRef = 19BEF4060C2291CE00275D06 /* colour.vowels2.xml */; };
19BEF4140C2291CE00275D06 /* colour.xml in Resources */ = {isa = PBXBuildFile; fileRef = 19BEF4070C2291CE00275D06 /* colour.xml */; };
19BEF4150C2291CE00275D06 /* colour.xsl in Resources */ = {isa = PBXBuildFile; fileRef = 19BEF4080C2291CE00275D06 /* colour.xsl */; };
- 19C190AB0C3267D700979F34 /* DasherViewAqua.h in Headers */ = {isa = PBXBuildFile; fileRef = 19C190A90C3267D700979F34 /* DasherViewAqua.h */; };
- 19C190AC0C3267D700979F34 /* DasherViewAqua.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19C190AA0C3267D700979F34 /* DasherViewAqua.mm */; };
19C1AE820B130F18005C68D3 /* COSXMouseInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 19C1AE810B130F18005C68D3 /* COSXMouseInput.h */; };
- 19E1AE4F0B0DB73300F3466C /* COSXDasherScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 19E1AE4D0B0DB73300F3466C /* COSXDasherScreen.h */; };
- 19E1AE500B0DB73300F3466C /* COSXDasherScreen.mm in Sources */ = {isa = PBXBuildFile; fileRef = 19E1AE4E0B0DB73300F3466C /* COSXDasherScreen.mm */; };
19E49DB50B10556100BA5CE8 /* DasherUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 196D8785048AA2750000000A /* DasherUtil.mm */; };
19E49DB60B10556200BA5CE8 /* DasherUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 196D8784048AA2750000000A /* DasherUtil.h */; };
- 19F36D8E0B18B60E002F41F1 /* ZippyStringImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F36D8A0B18B60E002F41F1 /* ZippyStringImage.h */; };
- 19F36D8F0B18B60E002F41F1 /* ZippyStringImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 19F36D8B0B18B60E002F41F1 /* ZippyStringImage.m */; };
- 19F36D900B18B60E002F41F1 /* ZippyStringGlyph.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F36D8C0B18B60E002F41F1 /* ZippyStringGlyph.h */; };
- 19F36D910B18B60E002F41F1 /* ZippyStringGlyph.m in Sources */ = {isa = PBXBuildFile; fileRef = 19F36D8D0B18B60E002F41F1 /* ZippyStringGlyph.m */; };
19F8C7E60C858A2800276B4F /* I18n.h in Headers */ = {isa = PBXBuildFile; fileRef = 19F8C7E50C858A2800276B4F /* I18n.h */; };
3300115210A2EA7700D31B1D /* ExpansionPolicy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3300115010A2EA7700D31B1D /* ExpansionPolicy.cpp */; };
3300115310A2EA7700D31B1D /* ExpansionPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 3300115110A2EA7700D31B1D /* ExpansionPolicy.h */; };
@@ -414,10 +401,6 @@
1921DB6D0C7ECB9900E6DAA5 /* GameScorer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = GameScorer.h; sourceTree = "<group>"; };
19351BF304575C6C0000000A /* mktar.sh */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.sh; path = mktar.sh; sourceTree = "<group>"; };
193731A70C8586F20022CBC7 /* config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
- 1946CAB90481AD440000000A /* ZippyCache.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ZippyCache.h; sourceTree = "<group>"; };
- 1946CABA0481AD440000000A /* ZippyCache.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ZippyCache.m; sourceTree = "<group>"; };
- 1946CABB0481AD440000000A /* ZippyString.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ZippyString.h; sourceTree = "<group>"; };
- 1946CABC0481AD440000000A /* ZippyString.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ZippyString.m; sourceTree = "<group>"; };
1948BDF60C226CFC001DFA32 /* ActionButton.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ActionButton.cpp; sourceTree = "<group>"; };
1948BDF70C226CFC001DFA32 /* ActionButton.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ActionButton.h; sourceTree = "<group>"; };
1948BDFC0C226CFC001DFA32 /* AlphabetMap.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AlphabetMap.cpp; sourceTree = "<group>"; };
@@ -543,9 +526,8 @@
1948BE950C226CFD001DFA32 /* UserLogTrial.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = UserLogTrial.h; sourceTree = "<group>"; };
1948BE9A0C226CFD001DFA32 /* XMLUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = XMLUtil.cpp; sourceTree = "<group>"; };
1948BE9B0C226CFD001DFA32 /* XMLUtil.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = XMLUtil.h; sourceTree = "<group>"; };
- 19558AD50C3182730054A193 /* DasherViewCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DasherViewCocoa.h; sourceTree = "<group>"; };
- 196874000C2BDC2E00D63879 /* AlphabetLetter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AlphabetLetter.h; sourceTree = "<group>"; };
- 196874010C2BDC2E00D63879 /* AlphabetLetter.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = AlphabetLetter.mm; sourceTree = "<group>"; };
+ 196874000C2BDC2E00D63879 /* OpenGLScreen.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = OpenGLScreen.h; path = ../Common/OpenGLScreen.h; sourceTree = SOURCE_ROOT; };
+ 196874010C2BDC2E00D63879 /* OpenGLScreen.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = OpenGLScreen.mm; path = ../Common/OpenGLScreen.mm; sourceTree = SOURCE_ROOT; };
196874040C2BDC2E00D63879 /* GLUtils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = GLUtils.h; sourceTree = "<group>"; };
196874050C2BDC2E00D63879 /* GLUtils.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = GLUtils.mm; sourceTree = "<group>"; };
196874280C2BE12E00D63879 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = "<absolute>"; };
@@ -719,21 +701,13 @@
19BEF4060C2291CE00275D06 /* colour.vowels2.xml */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = colour.vowels2.xml; sourceTree = "<group>"; };
19BEF4070C2291CE00275D06 /* colour.xml */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = colour.xml; sourceTree = "<group>"; };
19BEF4080C2291CE00275D06 /* colour.xsl */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = colour.xsl; sourceTree = "<group>"; };
- 19C190A90C3267D700979F34 /* DasherViewAqua.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DasherViewAqua.h; sourceTree = "<group>"; };
- 19C190AA0C3267D700979F34 /* DasherViewAqua.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = DasherViewAqua.mm; sourceTree = "<group>"; };
19C1AE810B130F18005C68D3 /* COSXMouseInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COSXMouseInput.h; sourceTree = "<group>"; };
19C49619045029A40000000A /* DasherApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DasherApp.h; sourceTree = "<group>"; };
19C4961D045029D70000000A /* DasherViewOpenGL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DasherViewOpenGL.h; sourceTree = "<group>"; };
19D4423A0454667F0000000A /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/Preferences.nib; sourceTree = "<group>"; };
19D4423C04546C410000000A /* PreferencesController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PreferencesController.h; sourceTree = "<group>"; };
19D4423D04546C410000000A /* PreferencesController.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = PreferencesController.mm; sourceTree = "<group>"; };
- 19E1AE4D0B0DB73300F3466C /* COSXDasherScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COSXDasherScreen.h; sourceTree = "<group>"; };
- 19E1AE4E0B0DB73300F3466C /* COSXDasherScreen.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = COSXDasherScreen.mm; sourceTree = "<group>"; };
19EEDB310450E75F0000000A /* DasherApp.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = DasherApp.mm; sourceTree = "<group>"; };
- 19F36D8A0B18B60E002F41F1 /* ZippyStringImage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ZippyStringImage.h; sourceTree = "<group>"; };
- 19F36D8B0B18B60E002F41F1 /* ZippyStringImage.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ZippyStringImage.m; sourceTree = "<group>"; };
- 19F36D8C0B18B60E002F41F1 /* ZippyStringGlyph.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ZippyStringGlyph.h; sourceTree = "<group>"; };
- 19F36D8D0B18B60E002F41F1 /* ZippyStringGlyph.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ZippyStringGlyph.m; sourceTree = "<group>"; };
19F8C7E50C858A2800276B4F /* I18n.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = I18n.h; path = ../Common/I18n.h; sourceTree = SOURCE_ROOT; };
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = "<group>"; };
@@ -830,21 +804,14 @@
191180EA0B0FC91A001CB987 /* COSXSettingsStore.mm */,
191428E40B0E6CC6004F1C28 /* COSXDasherControl.h */,
191428E50B0E6CC6004F1C28 /* COSXDasherControl.mm */,
- 19E1AE4D0B0DB73300F3466C /* COSXDasherScreen.h */,
- 19E1AE4E0B0DB73300F3466C /* COSXDasherScreen.mm */,
19B57A74080D4E4900BCE3C6 /* AppWatcher.h */,
19B57A72080D4E4000BCE3C6 /* AppWatcher.m */,
19C49619045029A40000000A /* DasherApp.h */,
19EEDB310450E75F0000000A /* DasherApp.mm */,
1904CDA5048813400000000A /* DasherEdit.h */,
1904CDA6048813400000000A /* DasherEdit.mm */,
- 19558AD50C3182730054A193 /* DasherViewCocoa.h */,
- 19C190A90C3267D700979F34 /* DasherViewAqua.h */,
- 19C190AA0C3267D700979F34 /* DasherViewAqua.mm */,
19C4961D045029D70000000A /* DasherViewOpenGL.h */,
199DCCD70450B94C0000000A /* DasherViewOpenGL.mm */,
- 196874000C2BDC2E00D63879 /* AlphabetLetter.h */,
- 196874010C2BDC2E00D63879 /* AlphabetLetter.mm */,
330B91631292FE700022831C /* ModuleSettingsController.h */,
330B91611292FE510022831C /* ModuleSettingsController.mm */,
196874040C2BDC2E00D63879 /* GLUtils.h */,
@@ -861,14 +828,6 @@
198EC7B307153D6E00474B38 /* UnicharGenerator.m */,
196D8784048AA2750000000A /* DasherUtil.h */,
196D8785048AA2750000000A /* DasherUtil.mm */,
- 1946CAB90481AD440000000A /* ZippyCache.h */,
- 1946CABA0481AD440000000A /* ZippyCache.m */,
- 1946CABB0481AD440000000A /* ZippyString.h */,
- 1946CABC0481AD440000000A /* ZippyString.m */,
- 19F36D8C0B18B60E002F41F1 /* ZippyStringGlyph.h */,
- 19F36D8D0B18B60E002F41F1 /* ZippyStringGlyph.m */,
- 19F36D8A0B18B60E002F41F1 /* ZippyStringImage.h */,
- 19F36D8B0B18B60E002F41F1 /* ZippyStringImage.m */,
339055E61195FBD0001BE240 /* Queue.h */,
339055E71195FBD0001BE240 /* Queue.m */,
);
@@ -1265,6 +1224,8 @@
19F8C7E30C858A1500276B4F /* Common */ = {
isa = PBXGroup;
children = (
+ 196874000C2BDC2E00D63879 /* OpenGLScreen.h */,
+ 196874010C2BDC2E00D63879 /* OpenGLScreen.mm */,
19F8C7E50C858A2800276B4F /* I18n.h */,
);
name = Common;
@@ -1376,8 +1337,6 @@
buildActionMask = 2147483647;
files = (
1974FE340714861B00B95DA0 /* DasherApp.h in Headers */,
- 1974FE370714861B00B95DA0 /* ZippyCache.h in Headers */,
- 1974FE380714861B00B95DA0 /* ZippyString.h in Headers */,
198EC7B407153D6E00474B38 /* KeyboardEvent.h in Headers */,
198EC7B707153D6E00474B38 /* LowLevelKeyboardHandling.h in Headers */,
198EC7B807153D6E00474B38 /* UnicharGenerator.h in Headers */,
@@ -1385,13 +1344,10 @@
190257FD0B0C981300178CCD /* DasherEdit.h in Headers */,
190258010B0C981900178CCD /* DasherViewOpenGL.h in Headers */,
190258030B0C981900178CCD /* PreferencesController.h in Headers */,
- 19E1AE4F0B0DB73300F3466C /* COSXDasherScreen.h in Headers */,
191428E60B0E6CC6004F1C28 /* COSXDasherControl.h in Headers */,
191180EB0B0FC91A001CB987 /* COSXSettingsStore.h in Headers */,
19E49DB60B10556200BA5CE8 /* DasherUtil.h in Headers */,
19C1AE820B130F18005C68D3 /* COSXMouseInput.h in Headers */,
- 19F36D8E0B18B60E002F41F1 /* ZippyStringImage.h in Headers */,
- 19F36D900B18B60E002F41F1 /* ZippyStringGlyph.h in Headers */,
1948BE9E0C226CFD001DFA32 /* ActionButton.h in Headers */,
1948BEA30C226CFD001DFA32 /* AlphabetMap.h in Headers */,
1948BEA50C226CFD001DFA32 /* AlphIO.h in Headers */,
@@ -1454,10 +1410,8 @@
1948BF380C226CFD001DFA32 /* UserLogParam.h in Headers */,
1948BF3A0C226CFD001DFA32 /* UserLogTrial.h in Headers */,
1948BF3F0C226CFD001DFA32 /* XMLUtil.h in Headers */,
- 196874060C2BDC2E00D63879 /* AlphabetLetter.h in Headers */,
+ 196874060C2BDC2E00D63879 /* OpenGLScreen.h in Headers */,
1968740A0C2BDC2E00D63879 /* GLUtils.h in Headers */,
- 19558AD60C3182730054A193 /* DasherViewCocoa.h in Headers */,
- 19C190AB0C3267D700979F34 /* DasherViewAqua.h in Headers */,
1921DB3A0C7ECAA400E6DAA5 /* OneButtonDynamicFilter.h in Headers */,
1921DB3F0C7ECB4A00E6DAA5 /* DasherGameMode.h in Headers */,
1921DB6F0C7ECB9900E6DAA5 /* GameScorer.h in Headers */,
@@ -1513,7 +1467,14 @@
isa = PBXProject;
buildConfigurationList = 198D19FD08965C4800CE3CC9 /* Build configuration list for PBXProject "Dasher" */;
compatibilityVersion = "Xcode 2.4";
+ developmentRegion = English;
hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
mainGroup = 29B97314FDCFA39411CA2CEA /* MacOSX */;
projectDirPath = "";
projectRoot = "";
@@ -1738,8 +1699,6 @@
buildActionMask = 2147483647;
files = (
1974FE6B0714861B00B95DA0 /* main.m in Sources */,
- 1974FE6F0714861B00B95DA0 /* ZippyCache.m in Sources */,
- 1974FE700714861B00B95DA0 /* ZippyString.m in Sources */,
198EC7B507153D6E00474B38 /* KeyboardEvent.m in Sources */,
198EC7B607153D6E00474B38 /* LowLevelKeyboardHandling.c in Sources */,
198EC7B907153D6E00474B38 /* UnicharGenerator.m in Sources */,
@@ -1747,13 +1706,10 @@
190257FC0B0C980800178CCD /* DasherApp.mm in Sources */,
190257FE0B0C981400178CCD /* DasherEdit.mm in Sources */,
190258040B0C981A00178CCD /* PreferencesController.mm in Sources */,
- 19E1AE500B0DB73300F3466C /* COSXDasherScreen.mm in Sources */,
191427A80B0E0C68004F1C28 /* DasherViewOpenGL.mm in Sources */,
191428E70B0E6CC6004F1C28 /* COSXDasherControl.mm in Sources */,
191180EC0B0FC91A001CB987 /* COSXSettingsStore.mm in Sources */,
19E49DB50B10556100BA5CE8 /* DasherUtil.mm in Sources */,
- 19F36D8F0B18B60E002F41F1 /* ZippyStringImage.m in Sources */,
- 19F36D910B18B60E002F41F1 /* ZippyStringGlyph.m in Sources */,
1948BE9D0C226CFD001DFA32 /* ActionButton.cpp in Sources */,
1948BEA20C226CFD001DFA32 /* AlphabetMap.cpp in Sources */,
1948BEA40C226CFD001DFA32 /* AlphIO.cpp in Sources */,
@@ -1802,9 +1758,8 @@
1948BF370C226CFD001DFA32 /* UserLogParam.cpp in Sources */,
1948BF390C226CFD001DFA32 /* UserLogTrial.cpp in Sources */,
1948BF3E0C226CFD001DFA32 /* XMLUtil.cpp in Sources */,
- 196874070C2BDC2E00D63879 /* AlphabetLetter.mm in Sources */,
+ 196874070C2BDC2E00D63879 /* OpenGLScreen.mm in Sources */,
1968740B0C2BDC2E00D63879 /* GLUtils.mm in Sources */,
- 19C190AC0C3267D700979F34 /* DasherViewAqua.mm in Sources */,
1921DB390C7ECAA400E6DAA5 /* OneButtonDynamicFilter.cpp in Sources */,
1921DB400C7ECB4B00E6DAA5 /* DasherGameMode.cpp in Sources */,
1921DB6E0C7ECB9900E6DAA5 /* GameScorer.cpp in Sources */,
diff --git a/Src/MacOSX/DasherApp.h b/Src/MacOSX/DasherApp.h
index c120c68..8ebc205 100644
--- a/Src/MacOSX/DasherApp.h
+++ b/Src/MacOSX/DasherApp.h
@@ -11,9 +11,7 @@
#import <AppKit/AppKit.h>
#import "COSXDasherControl.h"
-//#import "DasherAppInterface.h"
-#import "COSXDasherScreen.h"
-#import "DasherViewCocoa.h"
+#import "DasherViewOpenGL.h"
#import "Queue.h"
@class AppWatcher;
@@ -24,7 +22,7 @@
IBOutlet NSPanel *dasherPanelUI;
COSXDasherControl *aquaDasherControl;
- id <DasherViewCocoa>dasherView;
+ DasherViewOpenGL *dasherView;
IBOutlet AppWatcher *appWatcher;
NSTimer *_timer;
@@ -34,7 +32,7 @@
- (void)start;
- (void)redraw;
-- (void)changeScreen:(COSXDasherScreen *)aScreen;
+- (void)changeScreen:(CDasherScreen *)aScreen;
- (void)pause;
- (void)unpause:(unsigned long int)time;
- (NSDictionary *)parameterDictionary;
@@ -50,8 +48,6 @@
- (void)windowWillClose:(NSNotification *)aNotification;
- (COSXDasherControl *)aquaDasherControl;
- (void)setAquaDasherControl:(COSXDasherControl *)value;
-- (id <DasherViewCocoa>)dasherView;
-- (void)setDasherView:(id <DasherViewCocoa>)value;
- (void)startTimer;
- (void)shutdownTimer;
- (NSTimer *)timer;
@@ -61,4 +57,6 @@
- (bool)supportsSpeech;
- (void)speak:(NSString *)sText interrupt:(bool)bInt;
- (void)copyToClipboard:(NSString *)sText;
+
+ property (assign) DasherViewOpenGL *dasherView;
@end
diff --git a/Src/MacOSX/DasherApp.mm b/Src/MacOSX/DasherApp.mm
index 2aed2cf..925c7da 100644
--- a/Src/MacOSX/DasherApp.mm
+++ b/Src/MacOSX/DasherApp.mm
@@ -10,9 +10,7 @@
#import "PreferencesController.h"
#import "DasherEdit.h"
#import "DasherUtil.h"
-#import "DasherViewCocoa.h"
#import "AppWatcher.h"
-#import "COSXDasherScreen.h"
/*
* Created by Doug Dickinson (dasher AT DressTheMonkey DOT plus DOT com), 18 April 2003
@@ -23,6 +21,8 @@
@implementation DasherApp
+ synthesize dasherView;
+
- (void)start {
// aquaDasherControl->Start();
}
@@ -31,7 +31,7 @@
aquaDasherControl->ScheduleRedraw();
}
-- (void)changeScreen:(COSXDasherScreen *)aScreen {
+- (void)changeScreen:(CDasherScreen *)aScreen {
aquaDasherControl->ChangeScreen( aScreen );
}
@@ -87,44 +87,36 @@
return self;
}
-- (IBAction)importTrainingText:(id)sender
-{
+- (IBAction)importTrainingText:(id)sender {
NSOpenPanel *op = [NSOpenPanel openPanel];
int returnCode = [op runModalForDirectory:nil file:nil types:nil];
- if (returnCode == NSOKButton)
- {
+ if (returnCode == NSOKButton) {
aquaDasherControl->Train([op filename]);
NSBeep();
- }
+ }
}
-- (IBAction)showPreferences:(id)sender
-{
+- (IBAction)showPreferences:(id)sender {
[[PreferencesController preferencesController] makeKeyAndOrderFront:sender];
}
-- (void)setPanelAlphaValue:(float)anAlphaValue
-{
+- (void)setPanelAlphaValue:(float)anAlphaValue {
[dasherPanelUI setAlphaValue:anAlphaValue];
}
- (void)finishRealization {
-
aquaDasherControl->Realize2();
- [dasherView finishRealization];
-
}
-- (void)awakeFromNib
-{
+- (void)awakeFromNib {
[dasherPanelUI setBecomesKeyOnlyIfNeeded:YES];
[dasherPanelUI setFloatingPanel:YES];
-
+
// TODO leave out until defaults works properly
// [self setPanelAlphaValue:[[NSUserDefaults standardUserDefaults] floatForKey:DASHER_PANEL_OPACITY]];
-
+
// not sure if this is the right place for this. if we ever have a local/remote switch (to control typing into self or others, it should probably be turned off/on there)
// not sure if this is the right call; is there an equivalent in the AXUI API? I can't find it...
// default value for seconds is 0.25, which makes the app miss eg mouse presses sometimes
@@ -144,17 +136,9 @@
}
- (void)setAquaDasherControl:(COSXDasherControl *)value {
- aquaDasherControl = value;
+ aquaDasherControl = value;
}
-- (id <DasherViewCocoa>)dasherView {
- return dasherView;
-}
-
-- (void)setDasherView:(id <DasherViewCocoa>)value {
- dasherView = value;
- }
-
- (void)startTimer {
#define FPS 40.0f
diff --git a/Src/MacOSX/DasherViewOpenGL.h b/Src/MacOSX/DasherViewOpenGL.h
index e038c16..6258ebd 100755
--- a/Src/MacOSX/DasherViewOpenGL.h
+++ b/Src/MacOSX/DasherViewOpenGL.h
@@ -7,25 +7,17 @@
//
-
+#import <OpenGL/gl.h>
#import <AppKit/NSOpenGLView.h>
#import <AppKit/NSNibDeclarations.h>
-#import "COSXDasherScreen.h"
-#import "AlphabetLetter.h"
#import "ColourIO.h"
-#import "DasherViewCocoa.h"
#import "KeyboardHelper.h"
- class NSColor, NSTimer, NSTextField, NSString, NSMutableDictionary;
- class NSBezierPath;
+ class NSString;
@class DasherApp;
+class COSXDasherScreen;
-typedef struct {
- float r, g, b;
-} colour_t;
-
-
- interface DasherViewOpenGL : NSOpenGLView <DasherViewCocoa> {
+ interface DasherViewOpenGL : NSOpenGLView {
COSXDasherScreen *aquaDasherScreen;
@@ -33,32 +25,18 @@ typedef struct {
NSTrackingRectTag trackingRectTag;
- NSString *_cachedFontName;
-
- NSMutableDictionary *_textAttributeCache;
-
- NSArray *_colourScheme;
+ NSString *cachedFontName;
GLuint frameBuffers[2];
GLuint textures[2];
- GLfloat texcoords[8];
+ GLfloat tc_x,tc_y;
///current (last successful) framebuffer width & height
int fw,fh;
- colour_t *colourTable;
-
- NSMutableDictionary *_letterDict;
CKeyboardHelper *_keyboardHelper;
-
- ///Caches for circleCallbackWithCentrePoint:... (see therein)
- float circ_rad;
- GLshort *circ_coords;
- int circPoints;
}
-- (void)sendMarker:(int)iMarker;
-- (void)displayCallback;
- (void)drawRect:(NSRect)rect;
- (void)mouseEntered:(NSEvent *)theEvent;
- (void)mouseExited:(NSEvent *)theEvent;
@@ -66,38 +44,19 @@ typedef struct {
- (void)mouseUp:(NSEvent *)e;
- (void)keyDown:(NSEvent *)e;
- (void)keyUp:(NSEvent *)e;
-- (void)circleCallbackCentrePoint:(NSPoint)aCentrePoint radius:(float)aRadius fillColourIndex:(int)aFillColourIndex outlineColorIndex:(int)anOutlineColorIndex lineWidth:(int)aLineWidth;
-- (void)rectangleCallbackX1:(int)x1 y1:(int)y1 x2:(int)x2 y2:(int)y2 fillColorIndex:(int)aFillColorIndex outlineColorIndex:(int)anOutlineColorIndex lineWidth:(int)aLineWidth;
-- (AlphabetLetter *)letterForString:(NSString *)aString;
-- (NSSize)textSizeCallbackWithString:(NSString *)aString size:(int)aSize;
-- (void)drawTextCallbackWithString:(NSString *)aString x1:(int)x1 y1:(int)y1 size:(int)aSize colorIndex:(int)aColorIndex;
-- (void)colourSchemeCallbackWithColourTable:(colour_t *)aColourTable;
-- (void)polygonCallbackPoints:(NSArray *)points fillColorIndex:(int)fColorIndex outlineColorIndex:(int)iColorIndex lineWidth:(int)aWidth;
-- (void)polylineCallbackPoints:(NSArray *)points width:(int)aWidth colorIndex:(int)aColorIndex;
- (id)initWithFrame:(NSRect)frame;
- (void)userDefaultsDidChange:(NSNotification *)aNote;
- (void)adjustTrackingRect;
- (BOOL)isFlipped;
- (BOOL)isOpaque;
- (void)awakeFromNib;
-- (void)finishRealization;
-- (COSXDasherScreen *)aquaDasherScreen;
- (BOOL)acceptsFirstResponder;
-- (NSArray *)colourScheme;
-- (void)setColourScheme:(NSArray *)newColourScheme;
-- (void)setColourSchemeFromColourInfo:(const CColourIO::ColourInfo *)pColourScheme;
-- (NSString *)cachedFontName;
-- (void)setCachedFontName:(NSString *)newCachedFontName;
- (void)dealloc;
- (void)gl_init;
- (void)reshape;
- (void) gl_reshape:(int)w :(int)h;
-- (void)flushCaches;
-
+- (void)redisplay;
- (NSPoint)mouseLocation;
-- (float)boundsWidth;
-- (float)boundsHeight;
-
+ property (retain) NSString *cachedFontName;
@end
-
diff --git a/Src/MacOSX/DasherViewOpenGL.mm b/Src/MacOSX/DasherViewOpenGL.mm
index df17a93..9a74852 100755
--- a/Src/MacOSX/DasherViewOpenGL.mm
+++ b/Src/MacOSX/DasherViewOpenGL.mm
@@ -18,11 +18,65 @@
#import "DasherApp.h"
#import "GLUtils.h"
-#import "COSXDasherScreen.h"
+#import "OpenGLScreen.h"
-#define MAX_CACHE_COUNT 1000
+ interface DasherViewOpenGL (private_methods)
+-(void)sendMarker:(int)iMarker;
+ end
+
+class COSXDasherScreen : public OpenGLScreen {
+ DasherViewOpenGL *dasherView;
+ NSDictionary *fontAttrs;
+public:
+ COSXDasherScreen(DasherViewOpenGL *_dasherView,screenint iWidth, screenint iHeight, GLfloat tc_x, GLfloat tc_y, GLuint *textures)
+ : OpenGLScreen(iWidth, iHeight, iWidth, iHeight,tc_x,tc_y,textures), dasherView(_dasherView), fontAttrs(nil) {
+ RegenerateLabels(); //no actual labels, so just initialize fontAttrs
+ }
+
+ ~COSXDasherScreen() {
+ [fontAttrs release];
+ }
+
+ void SendMarker(int iMarker) {
+ [dasherView sendMarker:iMarker];
+ }
+
+ void Display() {
+ OpenGLScreen::Display();
+ [[dasherView openGLContext] flushBuffer];
+ }
+
+ void resize(screenint w, screenint h,GLfloat tc_x,GLfloat tc_y) {
+ OpenGLScreen::resize(w,h, w,h, tc_x,tc_y);
+ }
+
+ void RegenerateLabels() {
+ [fontAttrs release];
+ //white text on (default) transparent background means that when we texture
+ //a surface using a colour, the text appears in that colour...
+ fontAttrs = [NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:dasherView.cachedFontName size:36.0],NSFontAttributeName,[NSColor whiteColor],NSForegroundColorAttributeName,nil];
+ //dictionaryWith...: does an autorelease - only "alloc" methods do not.
+ // But we want to keep the fontAttrs indefinitely...
+ [fontAttrs retain];
+ OpenGLScreen::RegenerateLabels();
+ }
+
+protected:
+ void RenderStringOntoCGContext(NSString *string, CGContextRef context) {
+ NSGraphicsContext *old = [NSGraphicsContext currentContext];
+ [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES]];
+
+ [string drawAtPoint:NSMakePoint(0.0, 0.0) withAttributes:fontAttrs];
+ [NSGraphicsContext setCurrentContext:old];
+ }
+
+ CGSize TextSize(NSString *str, unsigned int iFontSize) {
+ return NSSizeToCGSize([str sizeWithAttributes:[NSDictionary dictionaryWithObject:[NSFont fontWithName:dasherView.cachedFontName size:iFontSize] forKey:NSFontAttributeName]]);
+ }
+};
@implementation DasherViewOpenGL
+ synthesize cachedFontName;
/*
BEWARE!
@@ -31,12 +85,10 @@
- (void)sendMarker:(int)iMarker {
[[self openGLContext] makeCurrentContext];
- if (iMarker == -1)
- {
+ glFlush();
+ if (iMarker == -1) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- }
- else
- {
+ } else {
//NSLog(@"SendMarker %i\n",iMarker);
glDisable(GL_TEXTURE_2D);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frameBuffers[iMarker]);
@@ -49,26 +101,6 @@
glClear(GL_COLOR_BUFFER_BIT);
}
-- (void)displayCallback
-{
- [self sendMarker:-1];
- glEnable(GL_TEXTURE_2D);
- glColor4f(1.0, 1.0, 1.0, 1.0);
- NSSize r = [self bounds].size;
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- GLshort coords[] = {0,0, r.width,0, 0,r.height, r.width,r.height};
- glVertexPointer(2, GL_SHORT, 0, coords);
- glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
-
- for (int i=0; i<2; i++)
- {
- glBindTexture(GL_TEXTURE_2D, textures[i]);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- }
- glFlush();
-}
-
- (void)drawRect:(NSRect)rect {
//if (![dasherApp aquaDasherControl]->GetBoolParameter(BP_DASHER_PAUSED)) {
// (ACL) want to redraw even if paused, to get mouse line etc. So invoke
@@ -81,8 +113,6 @@
}
-
-
- (void)mouseEntered:(NSEvent *)theEvent
{
}
@@ -91,23 +121,20 @@
{
}
-- (void)mouseDown:(NSEvent *)e
-{
+- (void)mouseDown:(NSEvent *)e {
NSPoint q = [self convertPoint:[e locationInWindow] fromView:nil];
[dasherApp aquaDasherControl]->HandleClickDown(get_time(), q.x, q.y);
}
-- (void)mouseUp:(NSEvent *)e
-{
+- (void)mouseUp:(NSEvent *)e {
NSPoint q = [self convertPoint:[e locationInWindow] fromView:nil];
[dasherApp aquaDasherControl]->HandleClickUp(get_time(), q.x, q.y);
}
-- (void)keyDown:(NSEvent *)e
-{
+- (void)keyDown:(NSEvent *)e {
/*TODO, note that this isn't really "key down", rather it's "character entered"
or similar - if the key is held down long enough to repeat, we get multiple keyDowns
before a keyUp, and we just send them all along to the DasherCore code...*/
@@ -119,8 +146,7 @@
[dasherApp aquaDasherControl]->KeyDown(get_time(), keyCode);
}
-- (void)keyUp:(NSEvent *)e
-{
+- (void)keyUp:(NSEvent *)e {
NSString *chars = [e characters];
if ([chars length] > 1)
NSLog(@"KeyUp event for %i chars %@ - what to do? Ignoring all but first...\n", [chars length], chars);
@@ -129,180 +155,6 @@
[dasherApp aquaDasherControl]->KeyUp(get_time(), keyCode);
}
-- (void)circleCallbackCentrePoint:(NSPoint)aCentrePoint radius:(float)aRadius fillColourIndex:(int)aFillColourIndex outlineColorIndex:(int)anOutlineColorIndex lineWidth:(int)aLineWidth {
-
- //it's a bit of a hack, but we cache the last-computed set of points round the
- // as these are the same for all calls with the same radius - and (the hack!)
- // that the radius tends to be the same every time (as the only call to CDashe
- // is from CircleStartHandler!)...
- if (circ_rad != aRadius) {
- delete circ_coords;
- double costh=1.0f - 1.0f/(2.0f*aRadius);
- double th = acos(costh);
- int numPoints = circPoints = ceil(M_PI/th/2.0f); //for a quarter-circle
- double sinth = sin(th),x(aRadius),y(0.0);
- circ_coords = new GLshort[numPoints*8]; circ_rad = aRadius;
- circ_coords[0] = x; circ_coords[1] = y;
- for (int i=1; i<numPoints; i++) {
- double nx = x*costh - y*sinth;
- double ny = x*sinth + y*costh;
- circ_coords[2*i] = nx;
- circ_coords[2*i+1] = ny;
- x=nx; y=ny;
- }
- for (int i=0; i<numPoints; i++) {
- circ_coords[2*(i+numPoints)] = -circ_coords[2*i+1];
- circ_coords[2*(i+numPoints)+1] = circ_coords[2*i];
-
- circ_coords[2*(i+numPoints*2)] = -circ_coords[2*i];
- circ_coords[2*(i+numPoints*2)+1] = -circ_coords[2*i+1];
-
- circ_coords[2*(i+numPoints*3)] = circ_coords[2*i+1];
- circ_coords[2*(i+numPoints*3)+1] = -circ_coords[2*i];
- }
- }
-
- glDisable(GL_TEXTURE_2D);
- glEnableClientState(GL_VERTEX_ARRAY);
- glTranslatef(aCentrePoint.x, aCentrePoint.y, 0.0);
- if (aFillColourIndex!=-1) {
- glColor4f(colourTable[aFillColourIndex].r, colourTable[aFillColourIndex].g, colourTable[aFillColourIndex].b, 1.0f);
- glVertexPointer(2, GL_SHORT, 0, circ_coords);
- glDrawArrays(GL_TRIANGLE_FAN, 0, circPoints*4);
- }
- if (aLineWidth>0) {
- int oci = anOutlineColorIndex == -1 ? 3 : anOutlineColorIndex;
- glColor4f(colourTable[oci].r, colourTable[oci].g, colourTable[oci].b, 1.0f);
- glLineWidth(aLineWidth);
- glVertexPointer(2, GL_SHORT, 0, circ_coords);
- glDrawArrays(GL_LINE_LOOP, 0, circPoints*4);
- }
- glTranslatef(-aCentrePoint.x, -aCentrePoint.y, 0.0);
-}
-
-
-- (void)rectangleCallbackX1:(int)x1 y1:(int)y1 x2:(int)x2 y2:(int)y2 fillColorIndex:(int)aFillColorIndex outlineColorIndex:(int)oci lineWidth:(int)aLineWidth {
-
- // don't know if this is needed with opengl...does it cope with wonky coords?
- // float x, y, width, height;
- //
- // if( x2 > x1 ) {
- // x = x1;
- // width = x2 - x1;
- // }
- // else {
- // x = x2;
- // width = x1 - x2;
- // }
- //
- // if( y2 > y1 ) {
- // y = y1;
- // height = y2 - y1;
- // }
- // else {
- // y = y2;
- // height = y1 - y2;
- // }
- glDisable(GL_TEXTURE_2D);
- glEnableClientState(GL_VERTEX_ARRAY);
- if (aFillColorIndex!=-1) {
- glColor4f(colourTable[aFillColorIndex].r, colourTable[aFillColorIndex].g, colourTable[aFillColorIndex].b, 1.0);
- GLshort coords[8] = {x1,y1, x2,y1, x1,y2, x2,y2};
- glVertexPointer(2, GL_SHORT, 0, coords);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- }
-
- if (aLineWidth>0) {
- glColor4f(colourTable[oci].r, colourTable[oci].g, colourTable[oci].b, 1.0);
- glLineWidth(aLineWidth);
- GLshort coords[] = {x1,y1, x2,y1, x2,y2, x1,y2};
- glVertexPointer(2, GL_SHORT, 0, coords);
- glDrawArrays(GL_LINE_LOOP, 0, 4);
- }
-
-
-}
-
-
-- (AlphabetLetter *)letterForString:(NSString *)aString {
- AlphabetLetter *result = [_letterDict objectForKey:aString];
- if (result == nil) {
- result = [[AlphabetLetter alloc] initWithString:aString];
- [_letterDict setObject:result forKey:aString];
- }
- return result;
-}
-
-- (NSSize)textSizeCallbackWithString:(NSString *)aString size:(int)aSize
-{
- return [[self letterForString:aString] sizeWithSize:aSize];
-}
-
-
-- (void)drawTextCallbackWithString:(NSString *)aString x1:(int)x1 y1:(int)y1 size:(int)aSize colorIndex:(int)aColorIndex
-{
- AlphabetLetter *letter = [self letterForString:aString];
- glEnable(GL_TEXTURE_2D);
- // TODO could pass the whole colour_t in and let it deal with splitting out the items
- [letter drawWithSize:/*1.0*/ aSize x:x1 y:y1 r:colourTable[aColorIndex].r g:colourTable[aColorIndex].g b:colourTable[aColorIndex].b];
- glDisable(GL_TEXTURE_2D);
-}
-
-- (void)colourSchemeCallbackWithColourTable:(colour_t *)aColourTable {
-
- if (colourTable != NULL) {
- free(colourTable);
- }
-
- colourTable = aColourTable;
-}
-
-- (void)polygonCallbackPoints:(NSArray *)points fillColorIndex:(int)fColorIndex outlineColorIndex:(int)iColorIndex lineWidth:(int)iWidth {
- int len = [points count];
- if (len < 2) return;
- //1. fill...
- glDisable(GL_TEXTURE_2D);
- if (fColorIndex != -1) {
- glColor3f(colourTable[fColorIndex].r, colourTable[fColorIndex].g, colourTable[fColorIndex].b);
- glBegin(GL_TRIANGLE_FAN);
- for (int i = 0; i < len; i++)
- {
- NSPoint nsp = [[points objectAtIndex:i] pointValue];
- glVertex2i(nsp.x,nsp.y);
- }
- glEnd();
- }
- if (iWidth>0) {
- glColor3f(colourTable[iColorIndex].r,colourTable[iColorIndex].g,colourTable[iColorIndex].b);
- glLineWidth(iWidth);
- glBegin(GL_LINE_LOOP);
- for (int i = 0; i < len; i++)
- {
- NSPoint nsp = [[points objectAtIndex:i] pointValue];
- glVertex2i(nsp.x,nsp.y);
- }
- glEnd();
- }
-}
-
-- (void)polylineCallbackPoints:(NSArray *)points width:(int)aWidth colorIndex:(int)aColorIndex
-{
- int len = [points count];
- if (len < 2) return;
- glDisable(GL_TEXTURE_2D);
- glColor3f(colourTable[aColorIndex].r, colourTable[aColorIndex].g, colourTable[aColorIndex].b);
- glLineWidth(aWidth);
- glBegin(GL_LINE_STRIP);
- for (int i = 0; i < len; i++)
- {
- NSPoint nsp = [[points objectAtIndex:i] pointValue];
- glVertex2i(nsp.x,nsp.y);
- }
- glEnd();
-}
-
-
-
- (id)initWithFrame:(NSRect)aFrame {
NSOpenGLPixelFormatAttribute attrs[] =
{
@@ -321,7 +173,6 @@
if (self = [super initWithFrame:aFrame pixelFormat:pixFmt]) {
// init open gl
[self gl_init];
- [self flushCaches];
[self setFrameSize:aFrame.size];
//note these give us framebuffer _references_...
glGenFramebuffersEXT(2, frameBuffers);
@@ -333,126 +184,61 @@
glClear(GL_COLOR_BUFFER_BIT);
_keyboardHelper = new CKeyboardHelper();
- circ_rad=-1.0f;
}
return self;
}
- (void)userDefaultsDidChange:(NSNotification *)aNote {
- if (![[[NSUserDefaults standardUserDefaults] objectForKey:@"DasherFont"] isEqualToString:[self cachedFontName]]) {
- [self flushCaches];
- [dasherApp aquaDasherControl]->ScheduleRedraw();
+ //TODO also flush caches (i.e. glyphs) if alphabet changed?
+ NSString *newFont=[[NSUserDefaults standardUserDefaults] objectForKey:@"DasherFont"];
+ if (![newFont isEqualToString:self.cachedFontName]) {
+ self.cachedFontName=newFont;
+ aquaDasherScreen->RegenerateLabels();
+ [dasherApp redraw];
}
}
-- (void)flushCaches {
- [_letterDict release];
- _letterDict = [[NSMutableDictionary alloc] init];
- [self setCachedFontName:[[NSUserDefaults standardUserDefaults] objectForKey:@"DasherFont"]];
-}
-
-- (void)adjustTrackingRect
-{
+- (void)adjustTrackingRect {
// need this in order to get mouseEntered and Exited
// [self removeTrackingRect:trackingRectTag];
// trackingRectTag = [self addTrackingRect:[self frame] owner:self userData:nil assumeInside:[self isDashing]];
}
-- (BOOL)isFlipped
-{
+- (BOOL)isFlipped {
return YES;
// return NO;
}
-- (BOOL)isOpaque
-{
+- (BOOL)isOpaque {
return YES;
}
-- (void)awakeFromNib
-{
+- (void)awakeFromNib {
// aquaDasherScreen = new COSXDasherScreen(self);
[dasherApp setDasherView:self];
-
- [self adjustTrackingRect];
-
- [self flushCaches];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:NSUserDefaultsDidChangeNotification object:nil];
-}
+ self.cachedFontName=[[NSUserDefaults standardUserDefaults] objectForKey:@"DasherFont"];
-- (void)finishRealization {
+ NSSize sz = [self bounds].size;
+ aquaDasherScreen = new COSXDasherScreen(self, sz.width, sz.height, tc_x, tc_y, textures);
[dasherApp changeScreen:aquaDasherScreen];
-}
-
-- (COSXDasherScreen *)aquaDasherScreen {
- return aquaDasherScreen;
-}
-
-- (BOOL)acceptsFirstResponder
-{
- return YES;
-}
-
-
-- (NSArray *)colourScheme {
- return [[_colourScheme retain] autorelease];
-}
-
-- (void)setColourScheme:(NSArray *)newColourScheme {
- if (_colourScheme != newColourScheme) {
- [_colourScheme release];
- _colourScheme = [newColourScheme retain];
- }
-}
-
-- (void)setColourSchemeFromColourInfo:(const CColourIO::ColourInfo *)pColourScheme {
-
-
- int iNumColours = pColourScheme->Reds.size();
- colour_t *ct = (colour_t *)malloc(iNumColours * sizeof(colour_t));
-
- for(int i = 0; i < iNumColours; i++) {
- ct[i].r = pColourScheme->Reds[i] / 255.0;
- ct[i].g = pColourScheme->Greens[i] / 255.0;
- ct[i].b = pColourScheme->Blues[i] / 255.0;
- }
-
- // colour table must be freed elsewhere...
- [self colourSchemeCallbackWithColourTable:ct];
-}
-
-- (NSString *)cachedFontName {
- return _cachedFontName;
+ [self adjustTrackingRect];
}
-- (void)setCachedFontName:(NSString *)newCachedFontName {
- if (_cachedFontName != newCachedFontName) {
- NSString *oldValue = _cachedFontName;
- _cachedFontName = [newCachedFontName retain];
- [oldValue release];
- }
+- (BOOL)acceptsFirstResponder {
+ return YES;
}
-- (void)dealloc
-{
- [_cachedFontName release];
- [_textAttributeCache release];
+- (void)dealloc {
+ self.cachedFontName=nil;
[[self openGLContext] makeCurrentContext];
-
- if (colourTable != NULL) {
- free(colourTable);
- }
-
- [_letterDict release];
-
+
[super dealloc];
}
-
-- (void)gl_init
-{
+- (void)gl_init {
[[self openGLContext] makeCurrentContext];
//glClearColor(1.0, 1.0, 1.0, 1.0);
glShadeModel(GL_FLAT);
@@ -463,12 +249,12 @@
}
- (void)reshape {
- [self gl_reshape:[self bounds].size.width :[self bounds].size.height];
-
- delete( aquaDasherScreen );
- aquaDasherScreen = new COSXDasherScreen(self);
- [dasherApp changeScreen:aquaDasherScreen];
-
+ NSSize sz=[self bounds].size;
+ screenint w=sz.width,h=sz.height;
+ [self gl_reshape:w :h];
+ aquaDasherScreen->resize(w, h, tc_x, tc_y);
+ [dasherApp aquaDasherControl]->ScreenResized(aquaDasherScreen);
+
[self adjustTrackingRect];
}
@@ -494,11 +280,8 @@
}
fw=tw; fh=th;
}
- GLfloat tc_x = w/(double)tw, tc_y = h/(double)th;
- texcoords[0] = 0.0; texcoords[1] = tc_y;
- texcoords[2] = tc_x; texcoords[3] = tc_y;
- texcoords[4] = 0.0; texcoords[5] = 0.0;
- texcoords[6] = tc_x; texcoords[7] = 0.0;
+ tc_x = w/(double)tw;
+ tc_y = h/(double)th;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
@@ -514,14 +297,6 @@
return [self convertPoint:p fromView:nil];
}
-- (float)boundsWidth {
- return [self bounds].size.width;
-}
-
-- (float)boundsHeight {
- return [self bounds].size.height;
-}
-
- (void)redisplay {
[self setNeedsDisplay:YES];
}
diff --git a/Src/Win32/Common/WinUTF8.cpp b/Src/Win32/Common/WinUTF8.cpp
index 597ac78..085889b 100644
--- a/Src/Win32/Common/WinUTF8.cpp
+++ b/Src/Win32/Common/WinUTF8.cpp
@@ -85,6 +85,12 @@ void WinUTF8::UTF8string_to_wstring(const std::string &UTF8string, std::wstring
}
+std::wstring WinUTF8::UTF8string_to_wstring(const std::string &utf8string) {
+ std::wstring res;
+ UTF8string_to_wstring(utf8string,res);
+ return res;
+}
+
/////////////////////////////////////////////////////////////////////////////
void WinUTF8::wstring_to_UTF8string(const wstring &Input, string &Output) {
diff --git a/Src/Win32/Common/WinUTF8.h b/Src/Win32/Common/WinUTF8.h
index b038215..1c89a9b 100644
--- a/Src/Win32/Common/WinUTF8.h
+++ b/Src/Win32/Common/WinUTF8.h
@@ -23,6 +23,7 @@
namespace WinUTF8 {
void UTF8string_to_wstring(const std::string & UTF8string, std::wstring & Output);
+ std::wstring UTF8string_to_wstring(const std::string &UTF8string);
void wstring_to_UTF8string(const std::wstring & Input, std::string & Output);
}
#endif /* #ifndef __WinUTF8_h__ */
diff --git a/Src/Win32/Widgets/Canvas.cpp b/Src/Win32/Widgets/Canvas.cpp
index d668075..7ce700d 100644
--- a/Src/Win32/Widgets/Canvas.cpp
+++ b/Src/Win32/Widgets/Canvas.cpp
@@ -471,15 +471,9 @@ LRESULT CCanvas::OnMouseMove(UINT message, WPARAM wParam, LPARAM lParam, BOOL& b
}
LRESULT CCanvas::OnSize(UINT message, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {
- if(m_pScreen != 0) {
- delete m_pScreen;
- m_pScreen = 0;
- }
-
if (LOWORD(lParam)>0 && HIWORD(lParam) >0) {
- m_pScreen = new CScreen(m_hdc, m_hWnd, LOWORD(lParam), HIWORD(lParam));
- m_pScreen->SetFont(m_pDasherInterface->GetStringParameter(SP_DASHER_FONT));
- m_pDasherInterface->ChangeScreen(m_pScreen);
+ m_pScreen->resize(LOWORD(lParam), HIWORD(lParam));
+ m_pDasherInterface->ScreenResized(m_pScreen);
InvalidateRect( NULL, FALSE);
}
diff --git a/Src/Win32/Widgets/Screen.cpp b/Src/Win32/Widgets/Screen.cpp
index f3cd6fe..445f0b9 100644
--- a/Src/Win32/Widgets/Screen.cpp
+++ b/Src/Win32/Widgets/Screen.cpp
@@ -30,20 +30,31 @@ static char THIS_FILE[] = __FILE__;
/////////////////////////////////////////////////////////////////////////////
CScreen::CScreen(HDC hdc, HWND hWnd, Dasher::screenint iWidth, Dasher::screenint iHeight)
-:CDasherScreen(iWidth, iHeight), m_hdc(hdc) {
+:CLabelListScreen(iWidth, iHeight), m_hdc(hdc) {
// set up the off-screen buffers
// HDC hdc = GetDC(mainwindow);
m_hWnd = hWnd;
+ CreateBuffers();
+
+ CodePage = GetUserCodePage();
+
+// m_hDCScreen = ::GetDC(m_hwnd);
+// TCHAR debug[256];
+// _stprintf(debug, TEXT("GetDC: hwnd %x hdc %x\n"), m_hwnd, m_hDCScreen);
+// OutputDebugString(debug);
+}
+
+void CScreen::CreateBuffers() {
// Create a memory device context compatible with the screen
- m_hDCBufferBackground = CreateCompatibleDC(hdc); // one for rectangles
- m_hbmBitBackground = CreateCompatibleBitmap(hdc, m_iWidth, m_iHeight);
+ m_hDCBufferBackground = CreateCompatibleDC(m_hdc); // one for rectangles
+ m_hbmBitBackground = CreateCompatibleBitmap(m_hdc, GetWidth(), GetHeight());
SetBkMode(m_hDCBufferBackground, TRANSPARENT);
m_prevhbmBitBackground = SelectObject(m_hDCBufferBackground, m_hbmBitBackground);
- m_hDCBufferDecorations = CreateCompatibleDC(hdc);
- m_hbmBitDecorations = CreateCompatibleBitmap(hdc, m_iWidth, m_iHeight);
+ m_hDCBufferDecorations = CreateCompatibleDC(m_hdc);
+ m_hbmBitDecorations = CreateCompatibleBitmap(m_hdc, GetWidth(), GetHeight());
SetBkMode(m_hDCBufferDecorations, TRANSPARENT);
m_prevhbmBitDecorations = SelectObject(m_hDCBufferDecorations, m_hbmBitDecorations);
@@ -52,10 +63,13 @@ CScreen::CScreen(HDC hdc, HWND hWnd, Dasher::screenint iWidth, Dasher::screenint
m_hDCBuffer = m_hDCBufferBackground;
}
-
/////////////////////////////////////////////////////////////////////////////
CScreen::~CScreen() {
+ DeleteBuffers();
+}
+
+void CScreen::DeleteBuffers() {
// tidy up
// Select the old bitmaps back into the device contexts (is this really
@@ -89,6 +103,15 @@ void CScreen::SetColourScheme(const CColourIO::ColourInfo *pColours) {
m_pColours = pColours;
}
+void CScreen::SetFont(const string &strFont) {
+ if(FontName == strFont) return;
+ FontName = strFont;
+ for(stdext::hash_map<int, HFONT>::const_iterator it(m_cFonts.begin()); it != m_cFonts.end(); ++it)
+ DeleteObject(it->second);
+ m_cFonts.clear();
+ for (set<CLabelListScreen::Label*>::iterator it=LabelsBegin(); it!=LabelsEnd(); it++)
+ static_cast<CScreen::Label*>(*it)->m_sizeCache.clear();
+}
// Handler for redraw markers;
void CScreen::SendMarker(int iMarker) {
@@ -97,44 +120,27 @@ void CScreen::SendMarker(int iMarker) {
m_hDCBuffer = m_hDCBufferBackground;
break;
case 1:
- BitBlt(m_hDCBufferDecorations, 0, 0, m_iWidth, m_iHeight, m_hDCBufferBackground, 0, 0, SRCCOPY);
+ BitBlt(m_hDCBufferDecorations, 0, 0, GetWidth(), GetHeight(), m_hDCBufferBackground, 0, 0, SRCCOPY);
m_hDCBuffer = m_hDCBufferDecorations;
break;
}
}
-void CScreen::DrawMousePosBox(int which, int iMousePosDist,int layer) {
- RECT Rect;
- HBRUSH brush;
- switch (which) {
- case 0:
- Rect.left = 0;
- Rect.top = m_iHeight / 2 - iMousePosDist - 50;
- Rect.right = m_iWidth;
- Rect.bottom = Rect.top + 100;
- brush = CreateSolidBrush(RGB(255, 0, 0));
- break;
- case 1:
- Rect.left = 0;
- Rect.bottom = m_iHeight / 2 + iMousePosDist + 50;
- Rect.right = m_iWidth;
- Rect.top = Rect.bottom - 100;
- brush = CreateSolidBrush(RGB(255, 255, 0));
- break;
- default:
- DASHER_ASSERT(0);
- }
- FillRect(m_hDCBuffer, &Rect, brush);
- DeleteObject(brush);
- Display();
+void CScreen::resize(screenint width, screenint height) {
+ DeleteBuffers();
+ CLabelListScreen::resize(width,height);
+ CreateBuffers();
}
-void CScreen::DrawString(const std::string &OutputString, Dasher::screenint x1, Dasher::screenint y1, int iSize, int Colour) {
-
- Tstring OutputText;
+CScreen::Label::Label(CScreen *pScreen, const string &strText) : CLabelListScreen::Label(pScreen, strText), m_OutputText(WinUTF8::UTF8string_to_wstring(m_strText)) {
+}
- WinUTF8::UTF8string_to_wstring(OutputString, OutputText);
+CDasherScreen::Label *CScreen::MakeLabel(const string &strText) {
+ return new Label(this,strText);
+}
+void CScreen::DrawString(CDasherScreen::Label *lab, screenint x1, screenint y1, unsigned int iSize, int Colour) {
+ Label *label(static_cast<Label *>(lab));
RECT Rect;
Rect.left = x1;
Rect.top = y1;
@@ -152,54 +158,41 @@ void CScreen::DrawString(const std::string &OutputString, Dasher::screenint x1,
iCRefOld = SetTextColor(m_hDCBuffer, iCRefNew);
// The Windows API dumps all its function names in the global namespace, ::
- ::DrawText(m_hDCBuffer, OutputText.c_str(), OutputText.size(), &Rect, DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE);
+ ::DrawText(m_hDCBuffer, label->m_OutputText.c_str(), label->m_OutputText.size(), &Rect, DT_LEFT | DT_TOP | DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE);
SetTextColor(m_hDCBuffer, iCRefOld);
SelectObject(m_hDCBuffer, old);
}
-void CScreen::TextSize(const std::string &String, screenint *Width, screenint *Height, int iSize) {
- CTextSizeInput in;
- in.m_String = String;
- in.m_iSize = iSize;
+pair<screenint,screenint> CScreen::TextSize(CDasherScreen::Label *lab, unsigned int iSize) {
+ Label *label(static_cast<Label *>(lab));
// stdext::hash_map< CTextSizeInput, CTextSizeOutput, hash_textsize>::const_iterator it;
- std::map < CTextSizeInput, CTextSizeOutput >::const_iterator it;
- it = m_mapTextSize.find(in);
-
- if(it == m_mapTextSize.end()) {
- CTextSizeOutput out;
- TextSize_Impl(String, &out.m_iWidth, &out.m_iHeight, iSize);
-// m_mapTextSize.insert( stdext::hash_map< CTextSizeInput, CTextSizeOutput, hash_textsize>::value_type( in,out) );
- m_mapTextSize.insert(std::map < CTextSizeInput, CTextSizeOutput >::value_type(in, out));
- *Width = out.m_iWidth;
- *Height = out.m_iHeight;
- return;
- }
+ map<unsigned int,pair<screenint,screenint> >::const_iterator it = label->m_sizeCache.find(iSize);
+ if (it!=label->m_sizeCache.end()) return it->second;
- const CTextSizeOutput & out = it->second;
- *Width = out.m_iWidth;
- *Height = out.m_iHeight;
+ pair<screenint,screenint> res = TextSize_Impl(label, iSize);
+ label->m_sizeCache.insert(map<unsigned int,pair<screenint,screenint> >::value_type(iSize,res));
+ return res;
}
/////////////////////////////////////////////////////////////////////////////
-void CScreen::TextSize_Impl(const std::string &String, screenint *Width, screenint *Height, int iSize) {
+pair<screenint,screenint> CScreen::TextSize_Impl(CScreen::Label *label, unsigned int iSize) {
// TODO This function could be improved. The height of an "o" is returned as the
// same as the height of an "O". Perhaps GetGlyphOutline could help.
// Remember if it gets complicted, the height of each symbol could be pre-calculated
- wstring OutputText;
- WinUTF8::UTF8string_to_wstring(String, OutputText);
+ //wstring OutputText; //ACL assuming wstring is same as Tstring?
+ //WinUTF8::UTF8string_to_wstring(String, OutputText);
HFONT old = (HFONT) SelectObject(m_hDCBuffer, CScreen::GetFont(iSize));
// Get the dimensions of the text in pixels
SIZE OutSize;
- GetTextExtentPoint32(m_hDCBuffer, OutputText.c_str(), OutputText.size(), &OutSize);
+ GetTextExtentPoint32(m_hDCBuffer, label->m_OutputText.c_str(), label->m_OutputText.size(), &OutSize);
SelectObject(m_hDCBuffer, old);
- *Width = OutSize.cx;
- *Height = OutSize.cy;
+ return pair<screenint,screenint>(OutSize.cx,OutSize.cy);
}
/////////////////////////////////////////////////////////////////////////////
diff --git a/Src/Win32/Widgets/Screen.h b/Src/Win32/Widgets/Screen.h
index 14334bf..dd1cf61 100644
--- a/Src/Win32/Widgets/Screen.h
+++ b/Src/Win32/Widgets/Screen.h
@@ -27,7 +27,7 @@
/////////////////////////////////////////////////////////////////////////////
-class CScreen:public Dasher::CDasherScreen, private NoClones {
+class CScreen:public Dasher::CLabelListScreen, private NoClones {
public:
//Saves a lot of typing; typedefs are equal to their declaration & do not create distinct types.
typedef Dasher::screenint screenint;
@@ -40,12 +40,13 @@ public:
void DrawMousePosBox(int which, int iMousePosDist,int layer=0);
- void TextSize(const std::string & String, Dasher::screenint * Width, Dasher::screenint * Height, int Size);
+ //! Make label from UTF8-encoded string
+ CDasherScreen::Label *MakeLabel(const std::string &strText);
- //! Draw UTF8-encoded string String of size Size positioned at x1 and y1
-
- //void DrawString(const std::string & String, Dasher::screenint x1, Dasher::screenint y1, int Size,int layer=0);
- void DrawString(const std::string & String, Dasher::screenint x1, Dasher::screenint y1, int Size, int Colour);
+ std::pair<screenint,screenint> TextSize(CDasherScreen::Label *label, unsigned int Size);
+
+ //! Draw label at size Size positioned at x1 and y1
+ void DrawString(CDasherScreen::Label *label, screenint x1, screenint y1, unsigned int Size, int Colour);
void DrawRectangle(Dasher::screenint x1, Dasher::screenint y1, Dasher::screenint x2, Dasher::screenint y2, int Colour, int iOutlineColour, int iThickness);
@@ -86,13 +87,14 @@ public:
void SendMarker(int iMarker);
+ void resize(screenint w,screenint h);
private:
const void point2POINT(const point * In, POINT * Out, int Number);
- void TextSize_Impl(const std::string & String, Dasher::screenint * Width, Dasher::screenint * Height, int Size);
-
HWND m_hWnd;
+ void DeleteBuffers();
+ void CreateBuffers();
HDC m_hdc;
HDC m_hDCBuffer;
HDC m_hDCBufferBackground;
@@ -114,26 +116,14 @@ private:
stdext::hash_map <int, HFONT> m_cFonts; // Holds cached font sizes for current font
std::string FontName; // Shouldn't need to cache, should work on events to reset font cache
- struct CTextSizeInput {
- std::string m_String;
- int m_iSize;
-
- bool operator<(const CTextSizeInput & rhs) const {
- if(m_iSize < rhs.m_iSize)
- return true;
- if(m_iSize > rhs.m_iSize)
- return false;
- return m_String < rhs.m_String;
- } bool operator!=(const CTextSizeInput & rhs)const {
- return ((m_iSize != rhs.m_iSize) || (m_String != rhs.m_String));
- }};
- struct CTextSizeOutput {
- screenint m_iWidth;
- screenint m_iHeight;
+ class Label : public CLabelListScreen::Label {
+ public:
+ const Tstring m_OutputText;
+ Label(CScreen *pScreen, const std::string &strText);
+ map<unsigned int,pair<screenint,screenint> > m_sizeCache;
};
-
- mutable std::map < CTextSizeInput, CTextSizeOutput > m_mapTextSize;
+ std::pair<screenint,screenint> TextSize_Impl(CScreen::Label *label, unsigned int Size);
};
#include "Screen.inl"
diff --git a/Src/Win32/Widgets/Screen.inl b/Src/Win32/Widgets/Screen.inl
index 85dfffb..927850f 100644
--- a/Src/Win32/Widgets/Screen.inl
+++ b/Src/Win32/Widgets/Screen.inl
@@ -20,7 +20,7 @@ inline void CScreen::DrawRectangle(screenint x1, screenint y1, screenint x2, scr
#ifndef DASHER_WINCE
- if(m_iWidth != -1) {
+ if(GetWidth() != -1) {
point aPoints[5];
@@ -77,8 +77,8 @@ inline void CScreen::Polyline(point *Points, int Number, int iWidth, int iColour
inline void CScreen::Blank() {
RECT rect;
rect.top = 0;
- rect.right = long (m_iWidth);
- rect.bottom = long (m_iHeight);
+ rect.right = long (GetWidth());
+ rect.bottom = long (GetHeight());
rect.left = 0;
FillRect(m_hDCBuffer, &rect, (HBRUSH) GetStockObject(WHITE_BRUSH));
}
@@ -135,15 +135,6 @@ inline HBRUSH& CScreen::GetBrush(int iColor) {
return m_cBrushes[key];
}
-inline void CScreen::SetFont(const std::string &strFont) {
- if(FontName != strFont) {
- FontName = strFont;
- for(stdext::hash_map<int, HFONT>::const_iterator it(m_cFonts.begin()); it != m_cFonts.end(); ++it)
- DeleteObject(it->second);
- m_cFonts.clear();
- }
-}
-
inline HFONT& CScreen::GetFont(int iSize) {
// TODO: Reimplement
//if(FontName != m_pDasherInterface->GetStringParameter(SP_DASHER_FONT)) {
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.h b/Src/iPhone/Classes/CDasherInterfaceBridge.h
index 42cfd20..a274464 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.h
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.h
@@ -39,7 +39,7 @@ public:
~CDasherInterfaceBridge();
//redefinitions to make public....
- void OnUIRealised();
+ void Realize();//also calls OnUIRealised
void NewFrame(unsigned long iTime, bool bForceRedraw);
void SetTiltAxes(Vec3 main, float off, Vec3 slow, float off2);
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.mm b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
index fa1a09b..f197cfb 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.mm
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
@@ -27,8 +27,6 @@
using namespace std;
CDasherInterfaceBridge::CDasherInterfaceBridge(DasherAppDelegate *aDasherApp) : dasherApp(aDasherApp) {
- Realize();
- ExternalEventHandler(&CParameterNotificationEvent(SP_ALPHABET_ID)); //calls dasherApp::SetAlphabet
}
void CDasherInterfaceBridge::CreateModules() {
@@ -69,7 +67,11 @@ void CDasherInterfaceBridge::SetupUI() {
NSLog(@"CDasherInterfaceBridge::SetupUI");
}
-void CDasherInterfaceBridge::OnUIRealised() {CDasherInterfaceBase::OnUIRealised();}
+void CDasherInterfaceBridge::Realize() {
+ CDasherInterfaceBase::Realize();
+ ExternalEventHandler(&CParameterNotificationEvent(SP_ALPHABET_ID)); //calls dasherApp::SetAlphabet
+ CDasherInterfaceBase::OnUIRealised();
+}
void CDasherInterfaceBridge::SetupPaths() {
NSString *systemDir = [NSString stringWithFormat:@"%@/", [[NSBundle mainBundle] bundlePath]];
diff --git a/Src/iPhone/Classes/DasherAppDelegate.h b/Src/iPhone/Classes/DasherAppDelegate.h
index c40f898..0cbe972 100644
--- a/Src/iPhone/Classes/DasherAppDelegate.h
+++ b/Src/iPhone/Classes/DasherAppDelegate.h
@@ -8,7 +8,6 @@
#import <UIKit/UIKit.h>
#import "CDasherInterfaceBridge.h"
-#import "CDasherScreenBridge.h"
#import "TextView.h"
#import "Actions.h"
diff --git a/Src/iPhone/Classes/DasherAppDelegate.mm b/Src/iPhone/Classes/DasherAppDelegate.mm
index c4686d1..66860c9 100644
--- a/Src/iPhone/Classes/DasherAppDelegate.mm
+++ b/Src/iPhone/Classes/DasherAppDelegate.mm
@@ -26,6 +26,8 @@
- (void)doSpeedBtnImage:(NSString *)msg;
- (void)speedSlid:(id)slider;
- (CGRect)doLayout:(UIInterfaceOrientation)orient;
+//calls through to [EAGLView makeContextCurrent]
+- (void)selectEAGLContext;
@property (retain) UILabel *screenLockLabel;
@property (nonatomic,retain) NSString *m_wordBoundary;
@property (nonatomic,retain) NSString *m_sentenceBoundary;
@@ -56,6 +58,7 @@ static SModuleSettings _miscSettings[] = { //note iStep and string description a
@synthesize m_wordBoundary;
@synthesize m_sentenceBoundary;
@synthesize m_lineBoundary;
+
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
return NO;
@@ -161,13 +164,18 @@ static SModuleSettings _miscSettings[] = { //note iStep and string description a
[window addSubview:self.view];
+ //make object (this doesn't do anything much, initialization/Realize later
+ // - but we have to set a screen before we Realize)
+ _dasherInterface = new CDasherInterfaceBridge(self);
+
//create GUI components...
text = [[[TextView alloc] init] autorelease];
messageLabel = [[[UILabel alloc] init] autorelease];
tools = [[UIToolbar alloc] init]; //retain a reference (until dealloc) because of rotation
glView = [[[EAGLView alloc] initWithFrame:[self doLayout:UIInterfaceOrientationPortrait] Delegate:self] autorelease];
+ //that last, calls ChangeScreen on the interface, so now we can:
- //start training in a separate thread. (Has to be after first
+ //start Realization i.e. training in a separate thread. (Has to be after first
// call to doLayout, or get a black band across top of screen)
[self doAsyncLocked:@"Initializing..." target:self selector:@selector(initDasherInterface) param:nil];
@@ -223,7 +231,7 @@ static SModuleSettings _miscSettings[] = { //note iStep and string description a
- (void)initDasherInterface {
//training takes too long to perform in applicationDidFinishLaunching;
// so we do it here instead (having let the main thread display a "training" message);
- _dasherInterface = new CDasherInterfaceBridge(self);
+ _dasherInterface->Realize();
//the rest has to be done on the main thread to avoid problems with OpenGL contexts
// (which are local to one thread); however, we'll have the background thread wait...
[self performSelectorOnMainThread:@selector(finishStartup) withObject:nil waitUntilDone:YES];
@@ -232,11 +240,8 @@ static SModuleSettings _miscSettings[] = { //note iStep and string description a
}
- (void)finishStartup {
- self.dasherInterface->ChangeScreen(new CDasherScreenBridge(glView));
-
[CalibrationController doSetup]; //restore tilt settings
[self notifySpeedChange];
- self.dasherInterface->OnUIRealised(); //that does startAnimation...
doneSetup = YES;
//The following will cause the text cursor to be displayed whenever
// any change is made to the textbox...
@@ -521,6 +526,10 @@ static SModuleSettings _miscSettings[] = { //note iStep and string description a
return text.text;
}
+-(void)selectEAGLContext {
+ [glView makeContextCurrent];
+}
+
#pragma mark TextViewDelegate methods
-(void)textViewDidChangeSelection:(UITextView *)textView {
@@ -602,11 +611,14 @@ static SModuleSettings _miscSettings[] = { //note iStep and string description a
- (void)aSyncMain:(NSInvocation *)action {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ //This method is being executed on (some, unknown) background thread, i.e. not the main thread.
+ // We don't _know_ it's going to do anything OpenGL-related, but to mirror the main thread:
+ [[DasherAppDelegate theApp] selectEAGLContext];
[action invoke];
+ [DasherAppDelegate theApp].screenLockLabel = nil;
//passing 'nil' here, where a BOOL is expected, is a horrendous trick - nil = 0x0 is effectively reinterpret_casted...
// however, the 'correct' method of passing [NSNumber numberWithBool:] is erratic, resulting in either inversion,
// always true, or always false, on different versions of the iPhone OS/SDK...
- [DasherAppDelegate theApp].screenLockLabel = nil;
[self performSelectorOnMainThread:@selector(dismissModalViewControllerAnimated:) withObject:nil waitUntilDone:NO];
[pool release];
}
diff --git a/Src/iPhone/Classes/EAGLView.h b/Src/iPhone/Classes/EAGLView.h
index 51d1aea..7e58bf5 100644
--- a/Src/iPhone/Classes/EAGLView.h
+++ b/Src/iPhone/Classes/EAGLView.h
@@ -12,43 +12,57 @@
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
-#import "DasherScreenCallbacks.h"
+#import "../Common/OpenGLScreen.h"
#import "DasherAppDelegate.h"
+ class EAGLView;
+
+class CDasherScreenBridge : public OpenGLScreen {
+ EAGLView *view;
+public:
+ CDasherScreenBridge(EAGLView *_view, screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y, GLuint *textures);
+ ///Only for EAGLView to call...
+ void resize(screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y);
+ bool GetTouchCoords(screenint &iX, screenint &iY);
+ void Display();
+ void SendMarker(int iMarker);
+
+protected:
+ void RenderStringOntoCGContext(NSString *str, CGContextRef context);
+ CGSize TextSize(NSString *str, unsigned int iFontSize);
+};
+
/*
This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass.
The view content is basically an EAGL surface you render your OpenGL scene into.
Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel.
*/
- interface EAGLView : UIView<DasherScreenCallbacks> {
+ interface EAGLView : UIView {
@private
EAGLContext *context;
+ CDasherScreenBridge *dasherScreen;
+
/* OpenGL names for the renderbuffer and framebuffers used to render to this view */
GLuint viewRenderbuffer, viewFramebuffer;
BOOL animating, doneLayout, anyDown;
NSTimeInterval animationInterval;
DasherAppDelegate *dasherApp;
- colour_t *colourTable;
- GLuint mouseBuffer, boxesBuffer;
- GLuint mouseTex, boxesTex;
- GLshort rectcoords[8];
- GLfloat texcoords[8];
+ GLuint buffers[2];
+ GLuint textures[2];
+ GLint backingWidth, backingHeight;
+ GLfloat texw,texh;
CGPoint lastTouchCoords;
-
- ///Caches for circleCallbackWithCentrePoint:... (see therein)
- float circ_rad;
- GLshort *circ_coords;
- int circPoints;
-
}
@property (readonly,assign) CGPoint lastTouchCoords;
-
+//OpenGL context (needed to do any OGL operation) is only current per-thread, so must call this
+// if doing anything on any thread other than the main thread.
+-(void)makeContextCurrent;
- (void)startAnimation;
- (void)stopAnimation;
- (void)drawView;
diff --git a/Src/iPhone/Classes/EAGLView.mm b/Src/iPhone/Classes/EAGLView.mm
index c65d774..6a334f2 100644
--- a/Src/iPhone/Classes/EAGLView.mm
+++ b/Src/iPhone/Classes/EAGLView.mm
@@ -11,19 +11,59 @@
#import "EAGLView.h"
#import "DasherUtil.h"
-#import "AlphabetLetter.h"
+#import "../Common/OpenGLScreen.h"
// A class extension to declare private methods
@interface EAGLView ()
-
- (BOOL) createFramebuffer;
- (void) destroyFramebuffer;
-
+- (void)displayCallback;
+-(void)sendMarker:(int)iMarker;
+ property (readonly) bool readyToDisplay;
@end
+CDasherScreenBridge::CDasherScreenBridge(EAGLView *_view, screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y, GLuint *textures)
+: OpenGLScreen(iWidth, iHeight, backingWidth, backingHeight, tc_x, tc_y, textures), view(_view) {
+}
- implementation EAGLView
+void CDasherScreenBridge::resize(screenint iWidth, screenint iHeight, GLshort backingWidth, GLshort backingHeight, GLfloat tc_x, GLfloat tc_y) {
+ OpenGLScreen::resize(iWidth, iHeight, backingWidth, backingHeight, tc_x, tc_y);
+}
+
+bool CDasherScreenBridge::GetTouchCoords(screenint &iX, screenint &iY) {
+ CGPoint p = view.lastTouchCoords;
+ if (p.x==-1) return false;
+ iX=p.x; iY=p.y;
+ return true;
+}
+
+void CDasherScreenBridge::Display() {
+ if (!view.readyToDisplay) return; //can't display anything yet!
+ OpenGLScreen::Display();
+ [view displayCallback];
+};
+
+void CDasherScreenBridge::SendMarker(int iMarker) {
+ [view sendMarker:iMarker];
+}
+
+void CDasherScreenBridge::RenderStringOntoCGContext(NSString *str, CGContextRef context) {
+ UIGraphicsPushContext(context);
+ //white text on transparent background means that when we texture
+ //a surface using a colour, the text appears in that colour...
+ const CGFloat whiteComps[] = {1.0, 1.0, 1.0, 1.0};
+ CGColorRef white = CGColorCreate(CGBitmapContextGetColorSpace(context), whiteComps);
+ CGContextSetFillColorWithColor(context, white);
+ [str drawAtPoint:CGPointMake(0.0, 0.0) withFont:[UIFont systemFontOfSize:36]];
+ CGColorRelease(white);
+ UIGraphicsPopContext();
+}
+
+CGSize CDasherScreenBridge::TextSize(NSString *str, unsigned int iFontSize) {
+ return [str sizeWithFont:[UIFont systemFontOfSize:iFontSize]];
+}
+ implementation EAGLView
@synthesize lastTouchCoords;
// You must implement this method
@@ -31,7 +71,6 @@
return [CAEAGLLayer class];
}
-
- (id)initWithFrame:(CGRect)frame {
NSLog(@"initWithFrame needs delegate\n");
return nil;
@@ -41,7 +80,6 @@
if ((self = [super initWithFrame:frame])) {
dasherApp = _dasherApp;
- circ_rad=-1.0f;
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
@@ -59,9 +97,14 @@
glShadeModel(GL_FLAT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
+
+ glGenTextures(2, textures);
+ glGenFramebuffersOES(2, buffers);
+
animationInterval = 1.0 / 60.0;
- colourTable = nil;
+ //textures is a pointer to 2 ints, so even tho the ints haven't been init'd yet, we can still pass the ptr
+ dasherScreen = new CDasherScreenBridge(self, frame.size.width, frame.size.height, 0, 0, 0, 0, textures);
+ dasherApp.dasherInterface->ChangeScreen(dasherScreen);
}
return self;
}
@@ -100,19 +143,16 @@
}
}
-
- (void)layoutSubviews {
- [EAGLContext setCurrentContext:context];
- [self destroyFramebuffer];
- [self createFramebuffer];
- if (doneLayout)
- dasherApp.dasherInterface->ChangeScreen(new CDasherScreenBridge(self));
- else //first time, DasherAppDelegate will create screen as part of startup
- doneLayout = YES;
+ [EAGLContext setCurrentContext:context];
+ [self destroyFramebuffer];
+ [self createFramebuffer];
+ CGSize sz = [self bounds].size;
+ dasherScreen->resize(sz.width, sz.height, backingWidth, backingHeight, texw, texh);
+ doneLayout = YES;
[self drawView];
}
-
- (BOOL)createFramebuffer {
//dasherApp.dasherInterface->ChangeView();//???
glGenFramebuffersOES(1, &viewFramebuffer);
@@ -124,7 +164,7 @@
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
//CGRect r = [self bounds];
//glViewport(r.origin.x, r.origin.y, r.size.width, r.size.height);
- int backingWidth, backingHeight;
+
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
@@ -137,35 +177,19 @@
int w=1, h=1;
while (w < backingWidth) w <<= 1;
while (h < backingHeight) h <<= 1;
- //boxes buffer
- glGenTextures(1, &boxesTex);
- glGenFramebuffersOES(1, &boxesBuffer);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, boxesBuffer);
- glBindTexture(GL_TEXTURE_2D, boxesTex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
- glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, boxesTex, 0);
- if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
- {
- NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
- return NO;
- }
-
- //mouse buffer
- glGenTextures(1, &mouseTex);
- glGenFramebuffersOES(1, &mouseBuffer);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, mouseBuffer);
- glBindTexture(GL_TEXTURE_2D, mouseTex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
- glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, mouseTex, 0);
- if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
- {
- NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
- return NO;
- }
+
+ for (int i=0; i<(sizeof(textures)/sizeof(textures[0])); i++) {
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, buffers[i]);
+ glBindTexture(GL_TEXTURE_2D, textures[i]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nil);
+ glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, textures[i], 0);
+ if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
+ NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
+ return NO;
+ }
+ }
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@@ -176,32 +200,27 @@
glOrthox(0, IntToFixed(backingWidth), IntToFixed(backingHeight), 0, IntToFixed(-1), IntToFixed(1));
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
-
- rectcoords[0] = rectcoords[1] = 0;
- rectcoords[2] = backingWidth; rectcoords[3] = 0;
- rectcoords[4] = 0; rectcoords[5] = backingHeight;
- rectcoords[6] = backingWidth; rectcoords[7] = backingHeight;
- GLfloat texw = backingWidth/(float)w, texh = backingHeight/(float)h;
- texcoords[0] = 0.0; texcoords [1] = texh;//0.0;
- texcoords[2] = texw; texcoords[3] = texh;//0.0;
- texcoords[4] = 0.0; texcoords[5] = 0.0;//texh;
- texcoords[6] = texw; texcoords[7] = 0.0;//texh;
-
+ texw = backingWidth/(float)w, texh = backingHeight/(float)h;
+
return YES;
}
+-(bool)readyToDisplay {
+ return viewFramebuffer!=0;
+}
+
+-(void)makeContextCurrent {
+ [EAGLContext setCurrentContext:context];
+}
- (void)destroyFramebuffer {
glDeleteFramebuffersOES(1, &viewFramebuffer); viewFramebuffer = 0;
- glDeleteFramebuffersOES(1, &mouseBuffer); mouseBuffer = 0;
- glDeleteFramebuffersOES(1, &boxesBuffer); boxesBuffer = 0;
- glDeleteRenderbuffersOES(1, &viewRenderbuffer);
+ glDeleteRenderbuffersOES(1, &viewRenderbuffer);
viewRenderbuffer = 0;
}
-
- (void)startAnimation {
if (animating) return;
animating = YES;
@@ -211,7 +230,6 @@
[self setNeedsDisplay];
}
-
- (void)stopAnimation {
//stop for now at least - shutdown, settings dialog, etc.
// (causes drawView not to enqueue another repaint)
@@ -221,7 +239,13 @@
- (void)dealloc {
[self stopAnimation];
-
+
+ glDeleteFramebuffersOES(2, buffers);
+ glDeleteTextures(2,textures);
+ for (int i=0; i<2; i++)
+ buffers[i]=textures[i]=0;
+
+ [self destroyFramebuffer];
if ([EAGLContext currentContext] == context) {
[EAGLContext setCurrentContext:nil];
}
@@ -230,173 +254,21 @@
[super dealloc];
}
-//DasherScreenCallbacks...
--(void)blankCallback {};
-
-(void)displayCallback {
- if (!viewFramebuffer) return; //can't display anything yet!
- [self sendMarker:-1];
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
-
- glEnable(GL_TEXTURE_2D);
- glColor4f(1.0, 1.0, 1.0, 1.0);
-
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glVertexPointer(2, GL_SHORT, 0, rectcoords);
- glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
- for (int i=0; i<2; i++)
- {
- glBindTexture(GL_TEXTURE_2D, i==0 ? boxesTex : mouseTex);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- }
- glFlush();
- glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
- [context presentRenderbuffer:GL_RENDERBUFFER_OES];
-};
-
--(void)rectangleCallbackX1:(int)x1 y1:(int)y1 x2:(int)x2 y2:(int)y2 fillColorIndex:(int)aFillColorIndex outlineColorIndex:(int)anOutlineColorIndex lineWidth:(int)aLineWidth {
- glDisable(GL_TEXTURE_2D);
- glEnableClientState(GL_VERTEX_ARRAY);
- if (aFillColorIndex != -1) {
- glColor4f(colourTable[aFillColorIndex].r, colourTable[aFillColorIndex].g, colourTable[aFillColorIndex].b, 1.0);
- GLshort coords[8] = {x1,y1, x2,y1, x1,y2, x2,y2};
- glVertexPointer(2, GL_SHORT, 0, coords);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- }
- if (aLineWidth>0) {
- int oci = anOutlineColorIndex == -1 ? 3 : anOutlineColorIndex;
- glColor4f(colourTable[oci].r, colourTable[oci].g, colourTable[oci].b, 1.0);
- glLineWidth(aLineWidth);
- GLshort coords[] = {x1,y1, x2,y1, x2,y2, x1,y2};
- glVertexPointer(2, GL_SHORT, 0, coords);
- glDrawArrays(GL_LINE_LOOP, 0, 4);
- }
-}
-
--(void)circleCallbackCentrePoint:(CGPoint)aCentrePoint radius:(float)aRadius fillColourIndex:(int)aFillColourIndex outlineColorIndex:(int)anOutlineColorIndex lineWidth:(int)aLineWidth {
- //it's a bit of a hack, but we cache the last-computed set of points round the circle,
- // as these are the same for all calls with the same radius - and (the hack!) it happens
- // that the radius tends to be the same every time (as the only call to CDasherScreen::DrawCircle
- // is from CircleStartHandler!)...
- if (circ_rad != aRadius) {
- delete circ_coords;
- double costh=1.0f - 1.0f/(2.0f*aRadius);
- double th = acos(costh);
- int numPoints = circPoints = ceil(M_PI/th/2.0f); //for a quarter-circle
- double sinth = sin(th),x(aRadius),y(0.0);
- circ_coords = new GLshort[numPoints*8]; circ_rad = aRadius;
- circ_coords[0] = x; circ_coords[1] = y;
- for (int i=1; i<numPoints; i++) {
- double nx = x*costh - y*sinth;
- double ny = x*sinth + y*costh;
- circ_coords[2*i] = nx;
- circ_coords[2*i+1] = ny;
- x=nx; y=ny;
- }
- for (int i=0; i<numPoints; i++) {
- circ_coords[2*(i+numPoints)] = -circ_coords[2*i+1];
- circ_coords[2*(i+numPoints)+1] = circ_coords[2*i];
-
- circ_coords[2*(i+numPoints*2)] = -circ_coords[2*i];
- circ_coords[2*(i+numPoints*2)+1] = -circ_coords[2*i+1];
-
- circ_coords[2*(i+numPoints*3)] = circ_coords[2*i+1];
- circ_coords[2*(i+numPoints*3)+1] = -circ_coords[2*i];
- }
- }
-
- glDisable(GL_TEXTURE_2D);
- glEnableClientState(GL_VERTEX_ARRAY);
- glTranslatef(aCentrePoint.x, aCentrePoint.y, 0.0);
- if (aFillColourIndex!=-1) {
- glColor4f(colourTable[aFillColourIndex].r, colourTable[aFillColourIndex].g, colourTable[aFillColourIndex].b, 1.0);
- glVertexPointer(2, GL_SHORT, 0, circ_coords);
- glDrawArrays(GL_TRIANGLE_FAN, 0, circPoints*4);
- }
- if (aLineWidth>0) {
- int oci = anOutlineColorIndex == -1 ? 3 : anOutlineColorIndex;
- glColor4f(colourTable[oci].r, colourTable[oci].g, colourTable[oci].b, 1.0);
- glLineWidth(aLineWidth);
- glVertexPointer(2, GL_SHORT, 0, circ_coords);
- glDrawArrays(GL_LINE_LOOP, 0, circPoints*4);
- }
- glTranslatef(-aCentrePoint.x, -aCentrePoint.y, 0.0);
-};
-
--(CGSize)textSizeCallbackWithString:(NSString *)aString size:(int)aSize {
- return [aString sizeWithFont:[UIFont systemFontOfSize:aSize]];
-}
-
-- (void)drawTextCallbackWithString:(NSString *)aString x1:(int)x1 y1:(int)y1 size:(int)aSize colorIndex:(int)aColorIndex
-{
- AlphabetLetter *letter = [AlphabetLetter forString:aString];
- // TODO could pass the whole colour_t in and let it deal with splitting out the items
- [letter drawWithSize:aSize x:x1 y:y1 r:colourTable[aColorIndex].r g:colourTable[aColorIndex].g b:colourTable[aColorIndex].b];
+ glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
+ [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
-(void)sendMarker:(int)iMarker {
- if (iMarker != -1)
- {
- glDisable(GL_TEXTURE_2D);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, iMarker == 0 ? boxesBuffer : mouseBuffer);
- glClearColor(1.0, 1.0, 1.0, iMarker == 0 ? 1.0 : 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
- }
-}
-
--(void)polylineCallback:(int)iNum points:(Dasher::CDasherScreen::point *)points width:(int)iWidth colourIndex:(int)iColour {
- if (iNum < 2) return;
- GLshort *coords = new GLshort[iNum*2];
- for (int i = 0; i<iNum; i++)
- {
- coords[2*i] = points[i].x;
- coords[2*i+1] = points[i].y;
- }
- glDisable(GL_TEXTURE_2D);
- glColor4f(colourTable[iColour].r, colourTable[iColour].g, colourTable[iColour].b, 1.0);
- glLineWidth(iWidth);
- glVertexPointer(2, GL_SHORT, 0, coords);
- glDrawArrays(GL_LINE_STRIP, 0, iNum);
- delete coords;
-}
-
--(void)polygonCallback:(int)iNum points:(Dasher::CDasherScreen::point *)points fillColourIndex:(int)iFillColour outlineColourIndex:(int)iOutlineColour width:(int)iWidth {
- if (iNum < 2) return;
- GLshort *coords = new GLshort[iNum*2];
- for (int i = 0; i<iNum; i++)
- {
- coords[2*i] = points[i].x;
- coords[2*i+1] = points[i].y;
- }
- glDisable(GL_TEXTURE_2D);
- if (iFillColour != -1) {
- glColor4f(colourTable[iFillColour].r, colourTable[iFillColour].g, colourTable[iFillColour].b, 1.0);
- glVertexPointer(2, GL_SHORT, 0, coords);
- glDrawArrays(GL_TRIANGLE_FAN, 0, iNum);
- }
- if (iWidth>0) {
- glColor4f(colourTable[iOutlineColour].r, colourTable[iOutlineColour].g, colourTable[iOutlineColour].b, 1.0);
- glLineWidth(iWidth);
- glVertexPointer(2, GL_SHORT, 0, coords);
- glDrawArrays(GL_LINE_LOOP, 0, iNum);
- }
- delete coords;
-}
-
--(void)setColourSchemeWithColourTable:(colour_t *)aColourTable {
- if (colourTable != NULL) {
- free(colourTable);
- }
- colourTable = aColourTable;
-}
-
--(int)boundsWidth {
- return [self bounds].size.width;
+ if (iMarker == -1) {
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
+ } else {
+ glDisable(GL_TEXTURE_2D);
+ glBindFramebufferOES(GL_FRAMEBUFFER_OES, buffers[iMarker]);
+ glClearColor(1.0, 1.0, 1.0, iMarker == 0 ? 1.0 : 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
}
--(int)boundsHeight {
- return [self bounds].size.height;
-}
@end
diff --git a/Src/iPhone/Classes/IPhoneFilters.mm b/Src/iPhone/Classes/IPhoneFilters.mm
index acdd512..3713bc6 100644
--- a/Src/iPhone/Classes/IPhoneFilters.mm
+++ b/Src/iPhone/Classes/IPhoneFilters.mm
@@ -12,7 +12,7 @@
#include "../Common/Common.h"
#include "DasherInterfaceBase.h"
#include "Event.h"
-#include "CDasherScreenBridge.h"
+#include "EAGLView.h"
#include <iostream>
NSString *HOLD_TO_GO=@"HoldToGo";
diff --git a/Src/iPhone/Classes/IPhoneInputs.mm b/Src/iPhone/Classes/IPhoneInputs.mm
index 51991fb..a0aa967 100644
--- a/Src/iPhone/Classes/IPhoneInputs.mm
+++ b/Src/iPhone/Classes/IPhoneInputs.mm
@@ -11,6 +11,7 @@
#import "IPhoneInputs.h"
#import "DasherUtil.h"
#import "DasherAppDelegate.h"
+#import "EAGLView.h"
using namespace std;
using namespace Dasher;
diff --git a/Src/iPhone/Dasher.xcodeproj/project.pbxproj b/Src/iPhone/Dasher.xcodeproj/project.pbxproj
index fa7d40e..064f4b2 100755
--- a/Src/iPhone/Dasher.xcodeproj/project.pbxproj
+++ b/Src/iPhone/Dasher.xcodeproj/project.pbxproj
@@ -272,8 +272,7 @@
33CBB4F3101FA33E00510BF9 /* alphabet.swedish.xml in Resources */ = {isa = PBXBuildFile; fileRef = 33CBB4EB101FA33E00510BF9 /* alphabet.swedish.xml */; };
33CBB4F5101FA35900510BF9 /* training_basque_ES.txt in Resources */ = {isa = PBXBuildFile; fileRef = 33CBB4F4101FA35900510BF9 /* training_basque_ES.txt */; };
33DA5E2D11B70FA100011CD2 /* paste.png in Resources */ = {isa = PBXBuildFile; fileRef = 33DA5E2C11B70FA100011CD2 /* paste.png */; };
- 33EB483D0F7287DC0048E7C2 /* CDasherScreenBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33EB483C0F7287DC0048E7C2 /* CDasherScreenBridge.mm */; };
- 33EB49240F73E8B30048E7C2 /* AlphabetLetter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33EB49230F73E8B30048E7C2 /* AlphabetLetter.mm */; };
+ 33EB49240F73E8B30048E7C2 /* OpenGLScreen.mm in Sources */ = {isa = PBXBuildFile; fileRef = 33EB49230F73E8B30048E7C2 /* OpenGLScreen.mm */; };
33EC5DF70FF3E30D00275986 /* ButtonMultiPress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33EC5DF20FF3E30D00275986 /* ButtonMultiPress.cpp */; };
33EC5DF80FF3E30D00275986 /* FrameRate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33EC5DF40FF3E30D00275986 /* FrameRate.cpp */; };
33EC5DF90FF3E30D00275986 /* TwoPushDynamicFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33EC5DF50FF3E30D00275986 /* TwoPushDynamicFilter.cpp */; };
@@ -720,11 +719,8 @@
33CBB4EB101FA33E00510BF9 /* alphabet.swedish.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = alphabet.swedish.xml; sourceTree = "<group>"; };
33CBB4F4101FA35900510BF9 /* training_basque_ES.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = training_basque_ES.txt; sourceTree = "<group>"; };
33DA5E2C11B70FA100011CD2 /* paste.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = paste.png; sourceTree = "<group>"; };
- 33EB483B0F7287DC0048E7C2 /* CDasherScreenBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDasherScreenBridge.h; sourceTree = "<group>"; };
- 33EB483C0F7287DC0048E7C2 /* CDasherScreenBridge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CDasherScreenBridge.mm; sourceTree = "<group>"; };
- 33EB48400F72A5680048E7C2 /* DasherScreenCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DasherScreenCallbacks.h; sourceTree = "<group>"; };
- 33EB49220F73E8B30048E7C2 /* AlphabetLetter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlphabetLetter.h; sourceTree = "<group>"; };
- 33EB49230F73E8B30048E7C2 /* AlphabetLetter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AlphabetLetter.mm; sourceTree = "<group>"; };
+ 33EB49220F73E8B30048E7C2 /* OpenGLScreen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenGLScreen.h; sourceTree = "<group>"; };
+ 33EB49230F73E8B30048E7C2 /* OpenGLScreen.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenGLScreen.mm; sourceTree = "<group>"; };
33EC5DF20FF3E30D00275986 /* ButtonMultiPress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ButtonMultiPress.cpp; sourceTree = "<group>"; };
33EC5DF30FF3E30D00275986 /* ButtonMultiPress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButtonMultiPress.h; sourceTree = "<group>"; };
33EC5DF40FF3E30D00275986 /* FrameRate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameRate.cpp; sourceTree = "<group>"; };
@@ -776,10 +772,6 @@
337691850F9CEFC70083FEB2 /* InputMethodSelector.mm */,
3376916F0F9CE8630083FEB2 /* StringParamController.h */,
337691700F9CE8630083FEB2 /* StringParamController.mm */,
- 33EB49220F73E8B30048E7C2 /* AlphabetLetter.h */,
- 33EB49230F73E8B30048E7C2 /* AlphabetLetter.mm */,
- 33EB483B0F7287DC0048E7C2 /* CDasherScreenBridge.h */,
- 33EB483C0F7287DC0048E7C2 /* CDasherScreenBridge.mm */,
331C73F30F717594004492FF /* DasherUtil.h */,
331C73F40F717594004492FF /* DasherUtil.mm */,
331C73C10F71750D004492FF /* COSXSettingsStore.h */,
@@ -794,7 +786,6 @@
3354AF4711ADBAFD006CF570 /* Actions.mm */,
3324F7BD129D744D00EE6A22 /* ActionConfigurator.h */,
3324F7BE129D744D00EE6A22 /* ActionConfigurator.mm */,
- 33EB48400F72A5680048E7C2 /* DasherScreenCallbacks.h */,
339F8A310FF5088000282847 /* CalibrationController.h */,
339F8A320FF5088000282847 /* CalibrationController.mm */,
);
@@ -1334,6 +1325,8 @@
3344FE670F71718B00506EAA /* Common */ = {
isa = PBXGroup;
children = (
+ 33EB49220F73E8B30048E7C2 /* OpenGLScreen.h */,
+ 33EB49230F73E8B30048E7C2 /* OpenGLScreen.mm */,
334B1C2011233B8B007A6DFF /* ModuleSettings.h */,
332387350F7838AC00DD75C5 /* Platform.h */,
332387300F78388200DD75C5 /* Common.h */,
@@ -1414,7 +1407,14 @@
isa = PBXProject;
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Dasher" */;
compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
projectDirPath = "";
projectRoot = "";
@@ -1609,8 +1609,7 @@
3344FE660F71717C00506EAA /* XMLUtil.cpp in Sources */,
331C73C30F71750D004492FF /* COSXSettingsStore.mm in Sources */,
331C73F50F717594004492FF /* DasherUtil.mm in Sources */,
- 33EB483D0F7287DC0048E7C2 /* CDasherScreenBridge.mm in Sources */,
- 33EB49240F73E8B30048E7C2 /* AlphabetLetter.mm in Sources */,
+ 33EB49240F73E8B30048E7C2 /* OpenGLScreen.mm in Sources */,
337690140F989C870083FEB2 /* SBTree.cpp in Sources */,
337691710F9CE8630083FEB2 /* StringParamController.mm in Sources */,
337691860F9CEFC70083FEB2 /* InputMethodSelector.mm in Sources */,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]