From 4337660d464c16052152c5365c1d080cfce2261c Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 12 Sep 2015 12:20:30 +1000 Subject: [PATCH 01/30] ANDROID: fix method --- src/platform/android/jni/Android.mk | 2 +- src/platform/android/jni/freetype/Android.mk | 1 - src/platform/android/jni/runtime.cpp | 16 ++++-- .../net/sourceforge/smallbasic/AskResult.java | 37 +++++++++++++ .../sourceforge/smallbasic/MainActivity.java | 53 +++++++++++++------ 5 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 src/platform/android/src/net/sourceforge/smallbasic/AskResult.java diff --git a/src/platform/android/jni/Android.mk b/src/platform/android/jni/Android.mk index 1d087953..6e4643ac 100644 --- a/src/platform/android/jni/Android.mk +++ b/src/platform/android/jni/Android.mk @@ -7,7 +7,7 @@ JNI_PATH := $(call my-dir) SB_HOME := $(JNI_PATH)/../../../.. -FREETYPE_HOME := $(HOME)/android-sdk/freetype-2.5.5 +FREETYPE_HOME := $(HOME)/android-sdk/freetype-2.6 include $(call all-subdir-makefiles) LOCAL_PATH := $(JNI_PATH) diff --git a/src/platform/android/jni/freetype/Android.mk b/src/platform/android/jni/freetype/Android.mk index f702cf78..beece35d 100644 --- a/src/platform/android/jni/freetype/Android.mk +++ b/src/platform/android/jni/freetype/Android.mk @@ -31,7 +31,6 @@ LOCAL_SRC_FILES:= \ $(FREETYPE_HOME)/src/base/ftbitmap.c \ $(FREETYPE_HOME)/src/base/ftglyph.c \ $(FREETYPE_HOME)/src/base/ftstroke.c \ - $(FREETYPE_HOME)/src/base/ftxf86.c \ $(FREETYPE_HOME)/src/base/ftbase.c \ $(FREETYPE_HOME)/src/base/ftsystem.c \ $(FREETYPE_HOME)/src/base/ftinit.c \ diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index f00d7bd0..692d03ad 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -30,6 +30,7 @@ #define SERVER_SOCKET_KEY "serverSocket" #define SERVER_TOKEN_KEY "serverToken" #define MUTE_AUDIO_KEY "muteAudio" +#define OPT_IDE_KEY "optIde" Runtime *runtime; @@ -195,11 +196,15 @@ int Runtime::ask(const char *title, const char *prompt, bool cancel) { JNIEnv *env; _app->activity->vm->AttachCurrentThread(&env, NULL); jclass clazz = env->GetObjectClass(_app->activity->clazz); + jstring titleString = env->NewStringUTF(title); + jstring promptString = env->NewStringUTF(prompt); jmethodID methodId = env->GetMethodID(clazz, "ask", - "(Ljava/lang/String;Ljava/lang/String;)Z"); - jboolean result = (jboolean) env->CallBooleanMethod(_app->activity->clazz, methodId, - title, prompt); + "(Ljava/lang/String;Ljava/lang/String;Z)I"); + jint result = (jint) env->CallIntMethod(_app->activity->clazz, methodId, + titleString, promptString, cancel); env->DeleteLocalRef(clazz); + env->DeleteLocalRef(titleString); + env->DeleteLocalRef(promptString); _app->activity->vm->DetachCurrentThread(); return result; } @@ -390,6 +395,10 @@ void Runtime::loadConfig() { if (s && s->toInteger() == 1) { opt_mute_audio = 1; } + s = profile.get(OPT_IDE_KEY); + if (s) { + opt_ide = s->toInteger(); + } loadEnvConfig(profile, SERVER_SOCKET_KEY); loadEnvConfig(profile, SERVER_TOKEN_KEY); } @@ -417,6 +426,7 @@ void Runtime::saveConfig() { fprintf(fp, "%s='%s'\n", PATH_KEY, path); fprintf(fp, "%s=%d\n", FONT_SCALE_KEY, _fontScale); fprintf(fp, "%s=%d\n", MUTE_AUDIO_KEY, opt_mute_audio); + fprintf(fp, "%s=%d\n", OPT_IDE_KEY, opt_ide); for (int i = 0; environ[i] != NULL; i++) { char *env = environ[i]; if (strstr(env, SERVER_SOCKET_KEY) != NULL) { diff --git a/src/platform/android/src/net/sourceforge/smallbasic/AskResult.java b/src/platform/android/src/net/sourceforge/smallbasic/AskResult.java new file mode 100644 index 00000000..9d42750a --- /dev/null +++ b/src/platform/android/src/net/sourceforge/smallbasic/AskResult.java @@ -0,0 +1,37 @@ +package net.sourceforge.smallbasic; + +class AskResult { + private static final int ASK_YES = 0; + private static final int ASK_NO = 1; + private static final int ASK_CANCEL = 2; + int value; + + AskResult() { + value = ASK_CANCEL; + } + + public void setCancel() { + value = ASK_CANCEL; + } + + public void setNo() { + value = ASK_NO; + } + + public void setYes() { + value = ASK_YES; + } + + @Override + public String toString() { + switch (value) { + case ASK_YES: + return "Yes"; + case ASK_NO: + return "No"; + default: + return "cancel"; + } + } +} + diff --git a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java index 1109d2d2..66542455 100644 --- a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java +++ b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java @@ -40,6 +40,7 @@ import android.content.ClipboardManager; import android.content.Context; import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.res.Resources; import android.graphics.Rect; @@ -82,33 +83,53 @@ public class MainActivity extends NativeActivity { public static native void onResize(int width, int height); public static native void runFile(String fileName); - public boolean ask(String prompt, String accept, String cancel) { - // TODO: fixme - boolean result = false; - final Context context = this; + public int ask(final String title, final String prompt, final boolean cancel) { + final AskResult result = new AskResult(); + final Activity activity = this; final Semaphore mutex = new Semaphore(0); final Runnable runnable = new Runnable() { public void run() { - new AlertDialog.Builder(activity) - .setTitle(title).setMessage(message) - .setPositiveButton(accept, new DialogInterface.OnClickListener() { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(title).setMessage(prompt); + builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + result.setYes(); + mutex.release(); + } + }); + builder.setNegativeButton("No", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + result.setNo(); + mutex.release(); + } + }); + builder.setOnCancelListener(new OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + result.setCancel(); + mutex.release(); + } + }); + if (cancel) { + builder.setNeutralButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { + result.setCancel(); + mutex.release(); } - }) - .setPositiveButton(cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) {} - }).show(); - mutex.release(); + }); + } + builder.show(); } }; runOnUiThread(runnable); try { mutex.acquire(); } catch (InterruptedException e) { - Log.i(TAG, "getClipboardText failed: ", e); + Log.i(TAG, "ask failed: ", e); e.printStackTrace(); } - return result; + Log.i(TAG, "ask result=" + result); + return result.value; } public void clearSoundQueue() { @@ -221,7 +242,7 @@ public boolean onOptionsItemSelected(MenuItem item) { } return true; } - + @Override public boolean onPrepareOptionsMenu(Menu menu) { if (this._options != null) { @@ -265,7 +286,7 @@ public void run() { } }); } - + public void showAlert(final String title, final String message) { final Activity activity = this; runOnUiThread(new Runnable() { From f8d5fb4a999a22647c790d035ecd9e9f11b2d8ac Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 13 Sep 2015 10:19:53 +1000 Subject: [PATCH 02/30] ANDROID: fix display issues --- src/platform/android/jni/display.cpp | 9 ++----- src/ui/ansiwidget.cpp | 1 + src/ui/editor.cpp | 1 + src/ui/graphics.cpp | 2 +- src/ui/graphics.h | 35 ++++++++++++++-------------- src/ui/textedit.cpp | 15 +++++++++--- src/ui/textedit.h | 1 + 7 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/platform/android/jni/display.cpp b/src/platform/android/jni/display.cpp index 01adf6b5..b966a0a7 100644 --- a/src/platform/android/jni/display.cpp +++ b/src/platform/android/jni/display.cpp @@ -72,7 +72,7 @@ void Canvas::fillRect(int left, int top, int width, int height, pixel_t drawColo if (top + height > _h) { blockH = height - top; } - memset(getLine(top), drawColor, width * blockH); + memset(getLine(top), drawColor, 4 * width * blockH); } else { for (int y = 0; y < height; y++) { int posY = y + top; @@ -138,12 +138,7 @@ bool Graphics::construct() { if (_screen && _screen->create(_w, _h)) { _drawTarget = _screen; maSetColor(DEFAULT_BACKGROUND); -#if defined(PIXELFORMAT_RGBA8888) - int format = WINDOW_FORMAT_RGBA_8888; -#else - int format = WINDOW_FORMAT_RGB_565; -#endif - ANativeWindow_setBuffersGeometry(_app->window, 0, 0, format); + ANativeWindow_setBuffersGeometry(_app->window, 0, 0, WINDOW_FORMAT_RGBA_8888); result = true; } else { trace("Failed to create canvas"); diff --git a/src/ui/ansiwidget.cpp b/src/ui/ansiwidget.cpp index 3409d8e2..3ef3d785 100755 --- a/src/ui/ansiwidget.cpp +++ b/src/ui/ansiwidget.cpp @@ -587,6 +587,7 @@ void AnsiWidget::drawActiveButton() { } else if (_focus != NULL) { MAHandle currentHandle = maSetDrawTarget(HANDLE_SCREEN); _focus->drawShape(_activeButton); + _focus->drawLabel(); maUpdateScreen(); maSetDrawTarget(currentHandle); } diff --git a/src/ui/editor.cpp b/src/ui/editor.cpp index ff4f2040..a15b628e 100644 --- a/src/ui/editor.cpp +++ b/src/ui/editor.cpp @@ -98,6 +98,7 @@ void System::editSource(strlib::String &loadPath) { case SB_KEY_F(10): case SB_KEY_F(11): case SB_KEY_F(12): + case SB_KEY_MENU: redraw = false; break; case SB_KEY_ESCAPE: diff --git a/src/ui/graphics.cpp b/src/ui/graphics.cpp index eaf1fb48..1eebf9af 100644 --- a/src/ui/graphics.cpp +++ b/src/ui/graphics.cpp @@ -289,7 +289,7 @@ void Graphics::getImageData(Canvas *canvas, uint8_t *image, for (int dx = 0, x = srcRect->left; x < srcRect->width; x += scale, dx++) { if (x >= canvas->x() && x < canvas->w()) { uint8_t r,g,b; - GET_RGB(line[x], r, g, b); + GET_RGB2(line[x], r, g, b); int offs = (4 * dy * w) + (4 * dx); image[offs + 0] = r; image[offs + 1] = g; diff --git a/src/ui/graphics.h b/src/ui/graphics.h index 66627aac..a229afa4 100644 --- a/src/ui/graphics.h +++ b/src/ui/graphics.h @@ -21,35 +21,34 @@ using namespace strlib; -inline void RGB565_to_RGB(pixel_t c, uint8_t &r, uint8_t &g, uint8_t &b) { - r = (c >> 11) & 0x1f; - g = (c >> 5) & 0x3f; - b = (c) & 0x1f; +inline void RGB888_to_RGB(pixel_t c, uint8_t &r, uint8_t &g, uint8_t &b) { + r = (c & 0xff0000) >> 16; + g = (c & 0xff00) >> 8; + b = (c & 0xff); } -inline pixel_t RGB888_to_RGB565(unsigned rgb) { - return ((((rgb >> 19) & 0x1f) << 11) | - (((rgb >> 10) & 0x3f) << 5) | - (((rgb >> 3) & 0x1f))); +inline pixel_t RGB888_to_RGBA8888(unsigned c) { + uint8_t r = (c & 0xff0000) >> 16; + uint8_t g = (c & 0xff00) >> 8; + uint8_t b = (c & 0xff); + return ((0xff000000) | (b << 16) | (g << 8) | (r)); } -inline void RGB888_to_RGB(pixel_t c, uint8_t &r, uint8_t &g, uint8_t &b) { - r = (c & 0xff0000) >> 16; +inline void RGB888_BE_to_RGB(pixel_t c, uint8_t &r, uint8_t &g, uint8_t &b) { + b = (c & 0xff0000) >> 16; g = (c & 0xff00) >> 8; - b = (c & 0xff); + r = (c & 0xff); } -#if defined(PIXELFORMAT_RGB565) - #define SET_RGB(r, g, b) ((r << 11) | (g << 5) | (b)) - #define GET_RGB RGB565_to_RGB - #define GET_FROM_RGB888 RGB888_to_RGB565 -#elif defined(PIXELFORMAT_ARGB8888) +#if defined(PIXELFORMAT_RGBA8888) #define SET_RGB(r, g, b) ((0xff000000) | (r << 16) | (g << 8) | (b)) - #define GET_RGB RGB888_to_RGB - #define GET_FROM_RGB888(c) (0xff000000 | c) + #define GET_RGB RGB888_to_RGB + #define GET_RGB2 RGB888_BE_to_RGB + #define GET_FROM_RGB888 RGB888_to_RGBA8888 #else #define SET_RGB(r, g, b) ((r << 16) | (g << 8) | (b)) #define GET_RGB RGB888_to_RGB + #define GET_RGB2 RGB888_to_RGB #define GET_FROM_RGB888(c) (c) #endif diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 3d5a6651..ca00cdcd 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -264,6 +264,7 @@ TextEditInput::TextEditInput(const char *text, int chW, int chH, _cursorLine(0), _indentLevel(INDENT_LEVEL), _matchingBrace(-1), + _ptY(-1), _dirty(false) { stb_textedit_initialize_state(&_state, false); memset(_lineMarker, -1, sizeof(_lineMarker)); @@ -705,9 +706,17 @@ bool TextEditInput::updateUI(var_p_t form, var_p_t field) { } bool TextEditInput::selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw) { - stb_textedit_drag(&_buf, &_state, pt.x - _marginWidth, - pt.y + scrollY + (_scroll * _charHeight)); - redraw = true; + if (pt.x < _marginWidth) { + if (_ptY == -1 || (abs(pt.y - _ptY) > (_charHeight / 4))) { + lineNavigate(pt.y > _ptY); + redraw = true; + _ptY = pt.y; + } + } else { + stb_textedit_drag(&_buf, &_state, pt.x - _marginWidth, + pt.y + scrollY + (_scroll * _charHeight)); + redraw = true; + } return 1; } diff --git a/src/ui/textedit.h b/src/ui/textedit.h index adf39983..b81060fb 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -154,6 +154,7 @@ struct TextEditInput : public FormEditInput { int _indentLevel; int _matchingBrace; int _lineMarker[MAX_MARKERS]; + int _ptY; bool _dirty; }; From 4a6ca2b30a332c7d46a403c1be33d2e99bfc1874 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 14 Sep 2015 21:58:16 +1000 Subject: [PATCH 03/30] ANDROID: edit line no used for scrolling --- src/platform/sdl/main.cpp | 11 +++++--- src/ui/ansiwidget.cpp | 2 +- src/ui/editor.cpp | 7 +++++ src/ui/system.cpp | 57 +++++++++++---------------------------- src/ui/system.h | 1 - src/ui/textedit.cpp | 12 ++++++--- 6 files changed, 40 insertions(+), 50 deletions(-) diff --git a/src/platform/sdl/main.cpp b/src/platform/sdl/main.cpp index d488c439..b391b945 100644 --- a/src/platform/sdl/main.cpp +++ b/src/platform/sdl/main.cpp @@ -254,6 +254,7 @@ int main(int argc, char* argv[]) { char *runFile = NULL; bool debug = false; int fontScale; + int ide_option = -1; SDL_Rect rect; while (1) { @@ -301,11 +302,11 @@ int main(int argc, char* argv[]) { break; case 'r': runFile = strdup(optarg); - opt_ide = IDE_NONE; + ide_option = IDE_NONE; break; case 'e': runFile = strdup(optarg); - opt_ide = IDE_INTERNAL; + ide_option = IDE_INTERNAL; break; case 'm': opt_loadmod = 1; @@ -313,7 +314,7 @@ int main(int argc, char* argv[]) { break; case 'd': runFile = strdup(optarg); - opt_ide = IDE_EXTERNAL; + ide_option = IDE_EXTERNAL; debug = true; break; case 'p': @@ -334,6 +335,10 @@ int main(int argc, char* argv[]) { } restoreSettings(rect, fontScale, debug); + if (ide_option != -1) { + opt_ide = ide_option; + } + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS); SDL_Window *window = SDL_CreateWindow("SmallBASIC", rect.x, rect.y, rect.w, rect.h, diff --git a/src/ui/ansiwidget.cpp b/src/ui/ansiwidget.cpp index 3ef3d785..0e6d9424 100755 --- a/src/ui/ansiwidget.cpp +++ b/src/ui/ansiwidget.cpp @@ -141,7 +141,7 @@ void AnsiWidget::drawRectFilled(int x1, int y1, int x2, int y2) { flush(false, false, MAX_PENDING_GRAPHICS); } -// display and pending images changed +// display any pending images changed void AnsiWidget::flush(bool force, bool vscroll, int maxPending) { if (_front != NULL && _autoflush) { bool update = false; diff --git a/src/ui/editor.cpp b/src/ui/editor.cpp index a15b628e..4ef2d549 100644 --- a/src/ui/editor.cpp +++ b/src/ui/editor.cpp @@ -90,6 +90,13 @@ void System::editSource(strlib::String &loadPath) { _modifiedTime = getModifiedTime(); event.key = 0; } + if (editWidget->getControlMode()) { + if (event.key == 'e') { + event.key = SB_KEY_ESCAPE; + } else { + event.key = SB_KEY_CTRL(event.key); + } + } switch (event.key) { case SB_KEY_F(2): diff --git a/src/ui/system.cpp b/src/ui/system.cpp index af4e6149..1ac5a10b 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -34,14 +34,13 @@ #define MENU_EDITMODE 11 #define MENU_AUDIO 12 #define MENU_SCREENSHOT 13 -#define MENU_SCRATCHPAD 14 -#define MENU_UNDO 15 -#define MENU_REDO 16 -#define MENU_SAVE 17 -#define MENU_RUN 18 -#define MENU_DEBUG 19 -#define MENU_OUTPUT 20 -#define MENU_SIZE 21 +#define MENU_UNDO 14 +#define MENU_REDO 15 +#define MENU_SAVE 16 +#define MENU_RUN 17 +#define MENU_DEBUG 18 +#define MENU_OUTPUT 19 +#define MENU_SIZE 20 #define FONT_SCALE_INTERVAL 10 #define FONT_MIN 20 @@ -117,6 +116,7 @@ bool System::execute(const char *bas) { } int System::getPen(int code) { + _output->flush(true); int result = 0; if (!isClosing()) { switch (code) { @@ -129,7 +129,11 @@ int System::getPen(int code) { if (_touchX != -1 && _touchY != -1) { result = 1; } else { + // get mouse processEvents(0); + if (_touchX != -1 && _touchY != -1) { + result = 1; + } } break; @@ -292,9 +296,6 @@ void System::handleMenu(MAEvent &event) { case MENU_SCREENSHOT: ::screen_dump(); break; - case MENU_SCRATCHPAD: - scratchPad(); - break; case MENU_UNDO: event.type = EVENT_TYPE_KEY_PRESSED; event.key = SB_KEY_CTRL('z'); @@ -765,29 +766,23 @@ void System::showMenu() { items->add(new String("Show keypad")); _systemMenu[index++] = MENU_KEYPAD; #endif + items->add(new String("Screenshot")); + _systemMenu[index++] = MENU_SCREENSHOT; if (_mainBas) { - sprintf(buffer, "Scratchpad"); - items->add(new String(buffer)); sprintf(buffer, "Font Size %d%%", _fontScale - FONT_SCALE_INTERVAL); items->add(new String(buffer)); sprintf(buffer, "Font Size %d%%", _fontScale + FONT_SCALE_INTERVAL); items->add(new String(buffer)); - _systemMenu[index++] = MENU_SCRATCHPAD; _systemMenu[index++] = MENU_ZOOM_UP; _systemMenu[index++] = MENU_ZOOM_DN; - sprintf(buffer, "Editor [%s]", (opt_ide == IDE_NONE ? "OFF" : opt_ide == IDE_EXTERNAL ? "Live Mode" : "ON")); items->add(new String(buffer)); _systemMenu[index++] = MENU_EDITMODE; } - sprintf(buffer, "Audio [%s]", (opt_mute_audio ? "OFF" : "ON")); items->add(new String(buffer)); _systemMenu[index++] = MENU_AUDIO; - - items->add(new String("Screenshot")); - _systemMenu[index++] = MENU_SCREENSHOT; #if defined(_SDL) items->add(new String("Back")); _systemMenu[index++] = MENU_BACK; @@ -937,28 +932,6 @@ void System::printSource() { } } -void System::scratchPad() { - const char *path = gsb_bas_dir; -#if defined(_ANDROID) - path = "/sdcard/"; -#endif - char file[OS_PATHNAME_SIZE]; - sprintf(file, "%sscratch.bas", path); - bool ready = access(file, R_OK) == 0; - if (!ready) { - FILE *fp = fopen(file, "w"); - if (fp) { - fprintf(fp, "REM scratch buffer\n"); - fclose(fp); - ready = true; - } - } - if (ready) { - setLoadPath(file); - setExit(false); - } -} - void System::setExit(bool quit) { if (!isClosing()) { bool running = isRunning(); @@ -1089,7 +1062,7 @@ void lwrite(const char *str) { } void dev_delay(dword ms) { - g_system->getOutput()->redraw(); + g_system->getOutput()->flush(true); maWait(ms); } diff --git a/src/ui/system.h b/src/ui/system.h index 9bb383ee..5df684dc 100755 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -82,7 +82,6 @@ struct System { void printErrorLine(); void printSource(); void printSourceLine(char *text, int line, bool last); - void scratchPad(); void setRestart(); void showMenu(); void showSystemScreen(bool showSrc); diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index ca00cdcd..5be7d265 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -679,7 +679,9 @@ void TextEditInput::setCursorRow(int row) { } void TextEditInput::clicked(int x, int y, bool pressed) { - if (pressed) { + if (x < _marginWidth) { + _ptY = -1; + } else if (pressed) { stb_textedit_click(&_buf, &_state, x - _marginWidth, y + (_scroll * _charHeight)); } } @@ -707,8 +709,12 @@ bool TextEditInput::updateUI(var_p_t form, var_p_t field) { bool TextEditInput::selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw) { if (pt.x < _marginWidth) { - if (_ptY == -1 || (abs(pt.y - _ptY) > (_charHeight / 4))) { - lineNavigate(pt.y > _ptY); + int size = abs(pt.y - _ptY); + int minSize = _charHeight / 4; + if (_ptY == -1) { + _ptY = pt.y; + } else if (size > minSize) { + lineNavigate(pt.y < _ptY); redraw = true; _ptY = pt.y; } From 7a0bb66035f8b86086925b4a9624e249f6011f72 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 17 Sep 2015 18:20:02 +1000 Subject: [PATCH 04/30] SDL: update packaging --- ChangeLog | 4 ++ Makefile.am | 39 +----------------- configure.ac | 28 +++---------- debian/changelog | 5 +++ debian/rules | 8 +--- ide/android/AndroidManifest.xml | 2 +- ide/android/assets/main.bas | 4 +- images/sb-desktop-16x16.png | Bin 283 -> 985 bytes images/sb-desktop-32x32.png | Bin 462 -> 2858 bytes images/sb-desktop-48x48.png | Bin 0 -> 5544 bytes images/sb4w.ico | Bin 4150 -> 15086 bytes src/common/brun.c | 13 ++++-- src/platform/android/jni/runtime.cpp | 17 ++++++++ src/platform/sdl/Makefile.am | 12 +++--- src/platform/sdl/runtime.cpp | 10 ++++- src/platform/{fltk => sdl}/smallbasic.desktop | 8 ++-- src/platform/sdl/syswm.cpp | 3 +- src/ui/editor.cpp | 6 ++- src/ui/inputs.cpp | 14 +++---- src/ui/inputs.h | 4 +- src/ui/system.cpp | 12 +----- src/ui/system.h | 3 ++ src/ui/textedit.cpp | 29 +++++++------ 23 files changed, 103 insertions(+), 118 deletions(-) create mode 100644 images/sb-desktop-48x48.png rename src/platform/{fltk => sdl}/smallbasic.desktop (65%) diff --git a/ChangeLog b/ChangeLog index 9bdd3597..2c82f20f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2015-09-15 + SDL Update PEN(3) to work more like FLTK + Fix display output before PEN + 2015-08-26 Editor fixes: - now displays an i-beam/edit cursor diff --git a/Makefile.am b/Makefile.am index b29b8ef8..98db526f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ # SmallBASIC -# Copyright(C) 2001-2012 Chris Warren-Smith. +# Copyright(C) 2001-2015 Chris Warren-Smith. # # This program is distributed under the terms of the GPL v2.0 or later # Download the GNU Public License (GPL) from www.gnu.org @@ -7,43 +7,8 @@ SUBDIRS = @BUILD_SUBDIRS@ -EXTRA_DIST = \ - AUTHORS \ - ChangeLog \ - configure.in \ - NEWS \ - README \ - autogen.sh \ - documentation/export_csv.bas \ - documentation/sbasic_ref.csv \ - documentation/HOWTO/HOWTO-DOCUMENT.TXT \ - documentation/HOWTO/HOWTO-PORT.TXT \ - documentation/HOWTO/DEVELOP.TXT \ - documentation/LICENSE \ - documentation/README \ - documentation/README.UNIX \ - images/logo.gif \ - images/sb16x16.png \ - images/sb32x32.png \ - images/sb-desktop-16x16.png \ - images/sb-desktop-32x32.png \ - ide/smallbasic.lang \ - ide/small-basic-mode.el \ - ide/smallbasic.syn \ - rpm/README \ - rpm/SPECS/opensuse.spec - -install-exec-hook: - (mkdir -p $(DESTDIR)$(pkgdatadir) && \ - mkdir -p $(DESTDIR)$(pkgdatadir)/plugins && \ - mkdir -p $(DESTDIR)$(pkgdatadir)/ide && \ - mkdir -p $(DESTDIR)$(pkgdatadir)/samples && \ - cp documentation/sbasic_ref.csv $(DESTDIR)$(pkgdatadir) && \ - cp plugins/*.* $(DESTDIR)$(pkgdatadir)/plugins && \ - cp ide/*.* $(DESTDIR)$(pkgdatadir)/ide) - deb: - fakeroot dpkg-buildpackage + fakeroot dpkg-buildpackage -b test: (cd @TEST_DIR@ && make test) diff --git a/configure.ac b/configure.ac index c5309fcb..b16625b2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,13 +1,13 @@ dnl dnl Configure script for SmallBASIC dnl -dnl Copyright(C) 2001-2014 Chris Warren-Smith. +dnl Copyright(C) 2001-2015 Chris Warren-Smith. dnl dnl This program is distributed under the terms of the GPL v2.0 dnl Download the GNU Public License (GPL) from www.gnu.org dnl -AC_INIT([smallbasic], [0.11.20]) +AC_INIT([smallbasic], [0.11.21]) AC_CONFIG_SRCDIR([configure.ac]) AC_CANONICAL_TARGET @@ -204,6 +204,7 @@ function buildSDL() { dnl do not depend on cygwin.dll under cygwin build PACKAGE_CFLAGS="${PACKAGE_CFLAGS} -mms-bitfields" PACKAGE_LIBS="${PACKAGE_LIBS} -lwsock32 -lws2_32 -static-libgcc -static-libstdc++" + PACKAGE_LIBS="-Wl,-Bstatic ${PACKAGE_LIBS} `sdl2-config --static-libs` `freetype-config --libs`" AC_DEFINE(_Win32, 1, [Windows build]) ;; @@ -218,17 +219,10 @@ function buildSDL() { dnl backlinking support for modules PACKAGE_LIBS="${PACKAGE_LIBS} -ldl" PACKAGE_LIBS="${PACKAGE_LIBS} ${FONTCONFIG_LIBS}" + PACKAGE_LIBS="-static-libgcc ${PACKAGE_LIBS} `sdl2-config --static-libs` `freetype-config --libs`" esac PACKAGE_CFLAGS="${PACKAGE_CFLAGS} `sdl2-config --cflags` `freetype-config --cflags` -fno-exceptions" - case "${host_os}" in - *mingw*) - PACKAGE_LIBS="-Wl,-Bstatic ${PACKAGE_LIBS} `sdl2-config --static-libs` `freetype-config --libs`" - ;; - - *) - PACKAGE_LIBS="${PACKAGE_LIBS} `sdl2-config --libs` `freetype-config --libs`" - esac dnl preconfigured values for SDL build AC_DEFINE(_SDL, 1, [Defined when building SDL version]) @@ -339,19 +333,7 @@ function buildConsole() { AC_SUBST(BUILD_SUBDIRS) } -function buildDist() { - TARGET="Building source code release." - defaultConditionals - BUILD_SUBDIRS="src/common src/platform/gtk/src src/platform/gtk/data src/platform/gtk/icons" - BUILD_SUBDIRS="${BUILD_SUBDIRS} src/platform/fltk" - BUILD_SUBDIRS="${BUILD_SUBDIRS} src/platform/sdl" - BUILD_SUBDIRS="${BUILD_SUBDIRS} src/platform/unix" - AC_SUBST(BUILD_SUBDIRS) -} - -if test x$ac_build_dist = xyes; then - buildDist -elif test x$ac_build_fltk = xyes; then +if test x$ac_build_fltk = xyes; then buildFLTK elif test x$ac_build_sdl = xyes; then buildSDL diff --git a/debian/changelog b/debian/changelog index e98ebfa8..cb68d7cc 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,8 @@ +smallbasic (0.11.21) unstable; urgency=low + * Various - see web site + + -- Chris Warren-Smith Sat, 17 Sept 2015 09:45:25 +1000 + smallbasic (0.11.17) unstable; urgency=low * Fix compiler ignoring unused assignment values * Implement IMAGE diff --git a/debian/rules b/debian/rules index afded1fc..664b5148 100755 --- a/debian/rules +++ b/debian/rules @@ -28,7 +28,7 @@ endif ifneq "$(wildcard /usr/share/misc/config.guess)" "" cp -f /usr/share/misc/config.guess config.guess endif - ./configure $(CROSS) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs" --enable-fltk + ./configure $(CROSS) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --enable-sdl build: build-stamp @@ -69,17 +69,11 @@ binary-indep: build install binary-arch: build install dh_testdir dh_testroot - dh_installchangelogs ChangeLog - dh_installdocs - dh_installexamples - dh_install --exclude=".git" documentation/sbasic_ref.csv plugins samples/distro-examples usr/share/smallbasic - dh_installman dh_link dh_strip dh_compress dh_fixperms dh_installdeb - dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb diff --git a/ide/android/AndroidManifest.xml b/ide/android/AndroidManifest.xml index dc16476c..b9b56935 100644 --- a/ide/android/AndroidManifest.xml +++ b/ide/android/AndroidManifest.xml @@ -3,7 +3,7 @@ package="net.sourceforge.smallbasic" android:installLocation="preferExternal" android:versionCode="15" - android:versionName="0.11.19"> + android:versionName="0.11.21"> diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index c9608c08..73ef8f72 100644 --- a/ide/android/assets/main.bas +++ b/ide/android/assets/main.bas @@ -21,7 +21,6 @@ func mk_bn(value, lab, fg) bn.value = value bn.label = lab bn.color = fg - bn.backgroundColor = 0 mk_bn = bn end @@ -56,7 +55,7 @@ sub do_about() print "(_ ._ _ _.|||_) /\ (_ |/ " print "__)| | |(_||||_)/--\__)|\_" print - print "Version 0.11.20" + print "Version 0.11.21" print print "Copyright (c) 2002-2015 Chris Warren-Smith" print "Copyright (c) 1999-2006 Nic Christopoulos" + chr(10) @@ -202,7 +201,6 @@ sub main listFiles frm, path, basList, dirList frm.color = 10 - frm.backgroundColor = 0 rect 0, 0, xmax, lineSpacing COLOR 1 filled at 0, 0 make_ui = form(frm) diff --git a/images/sb-desktop-16x16.png b/images/sb-desktop-16x16.png index b389fe73a9012ff65a5937d92e9f32cba742ff2d..59471a4cdacbc8f55d18cb7d51c5bf8bd3cae236 100644 GIT binary patch delta 977 zcmV;?11|iV0@(*MiBL{Q4GJ0x0000DNk~Le0000G0000G2nGNE03Y-JVE_OC24YJ` zL;(K){{a7>y{D6rAsBxLbV*G`2j2-10wOB4gbhgm00U-8L_t(I%WacyOq2xx#((dh zyZ7$k?)Vol6a%`Dz}W(omJw@&q7~`d+FGUc!DVwneJB~5Te-gAS}RTYU@cf+|29}j zmRL3$1x6|2(dZD7zXErjcijK?-h1CZR2!?FZ_l%5&xdEvBk+GO^nBf`6y~@N=-!2@ zPo}!=E?X3-eBp>EU(UX?v#t2JyL~pX+Apjo-wuxLS1h)6LlDs=ndq4gMkf2vcJ3jm zYHTX0rMUlx1C_1KC;k)A-gl;>Ft1{7O4t7q3?P+at$7W*&Q`H)PNKB7nc3-K9^2Z| z)lgIX9DoRL>id83{kIHl?>FuqQYky3xIrjku%gTOeao!3t!GQwOU(5g=E=%880dNZ z*>k;Dn*fBj-sx0wD(;UPi0DF!e$NMNyK5hUEHi)OJC^hS5B_wKu6qq05$YMw)yOdH zl;zfN;;6|a?RfFcW))?-s)MS@l;_nmFx^8!OOTsY!_|M^4xuz2qs;F>*|3`{=U(BS zDL0C#VZ3_lE6Tb5}Erm=* ze&J!NQ8e3EVlb+e233RK7kc^h=DS=GRtUvYIBXjz$==P-)G2(i+qf5h#A0%x$i!GM~JAS_|$Q-;swOKokXzUq>&4sH?~Pk zk}}n`cx5r~(WQ(k2Ati*6A~Wd0;08nNt++9e4V=M*{n%b^K;3a*u!>wYI>8e@8dxU zATWP;de~b2xJxzXZ4|ULG!b4M>gRG{D?wqDj8G{v>ki_{DrH5uh&N*GoPK{_D}eM* zS%Km1-puS^K(%aYcwpASd)4KLi6T_(1}XUoR4tAgUd9{hYl@uwsP%u}_%~$xp1~G1 z{rqMzQSVC1M+9@KX+qG#!;y~H+F&fX+WZwK`+k5Mgj6ne00000NkvXXu0mjfJ!js5 literal 283 zcmV+$0p$LPP)63(50YZ0v13*NG!kvZqmD9 zfQ-Nfj6g&06!4N`9EIehFZ}1f``5vZ765!)Bz=k_8FI%#t$5gt7CKDQXV^g!ZC?w1 zfb6OVxX}s#6u0V)CkX&(`&x{CiV+Wmf&kDp!?t$ZoTlj@rj8-9l*3sF$)uBR(=|g< zyzOfd&Fe2`+@Br*TscdTZzs6b%H_m4#+CCH$>ZwXy2q1Oe)*7sVi~O%b^S#^`$ijQ h1;V!piEje2&MS)Y6Y{X$1sDUP5^$ zKuE$Pge2sh+~;}hz2}cWQQJDqbbmhQv-kO&wSQ}^eb!#TwFH+qR==~!ckSwz3ezIq zf9vSJgSMA=BQMV^&;QMq6=Jbh)^h##->9^^+UsoFX*gPU_}qi@=ew7JD=tOo!`%nJ z5e$aD>6dB*PJcRInF029A7J;-?qP15MeCxSU7LfMS0b0}!lG#%JZV>k=#nIv7PJa;tz zAKtosN`u$5<_|j#RKLCN)ad`$3B0*w-xHDC=wq%DrhnGGf|~OS1cvKi?ApZUw;rN% z`YlvRm#&OgC`?8UtEV9?E&^@Iip1Eb={H2#W$ zNA1sISbtvxeR$8jiulPP z7k|OZ*S3z!?_084Vwn<;itUdR4Ht3G*k#1M&Wqlk-z5+zA@Ij~C_UT5a~;b`dvNu* z#n5_+t_?q8zumyMA8tmOE^qDp5jk#v8?SmG)t&6Pe!=YV`#yI9p>Xai30IhDSK>ID z`+p}aCqGikiaiU7+i5&$^?EPC@dUc73(?j}JRPUP-N2c)(_D4gZS1OFPhs>beA6By z+-D#kp7=G%gye`_!?>##(}|Jch`{p~^qK%Gf4g%&f$+CHEszQ%0$Y0Y%POaT<|v-u z_VRR&G?93;7NsLg_vIc zARAA-Ohe}}iXx*xTX?3Q9BT+~?7N@QUXZ;r?(*{-@S;!zcgk=XLm2>|Y z87;)Gt%MPCM;ZQ5s3avtA6IG|seiFOa6E-AA<$fp>WO13fh{Gufx*lj{X8#!IG-cu zJ|UJ)5-pxaTO>*Xfg=S8!@^buo)R2A_c5Cr{);EBK2AaIc)mL=P3fWSKpy?-<(YuHx% z0t50UaH4Am1G28ekuFk!5CM+1Y~oDMA!d~?$1@~D3a2qX`yS%uQxT~i3JzD&BfJ_b zX*(k`G6Y&FlrYHYXl7gUlbi@=;H5fP8#1}kebj<;>3s_h+a8GpKhl$-8NWZD7KLP*Fo^7s$u2jq8+7;ME;b{`|_{QXAJ zl{0`(2S({^KgsP^t|c5SBB?dFs#oSb9XP_nZ{#y==rerO`Xukyf1m66Eai01$FwGD zxOwo;NqZ>}8c*5?A?Q4Jf(CXGGa9KkPtl(0$h90#3){PpVZae7gn#n0czgq`$zwRK z{!?IH9!u-33NG&y7NZ79Pdn88{t}W8`E& zBYb*h6*D4>x!xJesej^PGL?xC780BH4$bA-!A~$a5T(=bIxUH>D(y;wj*XWQ)%plcdGi=|{94)uPNXw_fZZp5 zz^pMJqLoM7ub}g6oz-qwwWH6}6G)tsE;UwAVK zvxx%ddVXa+MZd`1}~oE?SJVSTxsCAB5pfQjrqqx@1|NVpEv!z%W6y8Il!3wU*f1FN<+%@Q`CHt zQPsPt954pcv3pas)_59(s~B4MN2-R;;-&C%3Ug)QElB>36IX73 zn(_O7&)$)<@svPn6D}K6f zb5OR6r++f(bgS8a=1zV$Y7$3_Mo}Lbft%b$Niv(Z!E5kTG5rcx;m?>zRbiN2!>%CH z8iB2|usw&KuEs4L|GD?|&y{2i&aS%x84LGkI7&#MITR&P`Yesz^N5G)>36)1Pr@B^ zC)bfmo@7v;SHOgtehQy7Xw7P7V{jNVs+KUuJ%7vCrf(z4A7oe957rG7v>u@&J4xCQ zsdTJk>0c~L%N}_3=|FzjcZFg0M!E>l)$S;Sx7kZ4s!I@IG44DHapI+_8uAv z@1V8MSlTm(Vhe*bZ8QZdNUKHYMC9!gFMjR5FRhA`=T6NxY^T6qP(IlZd9*tJMsDDr z$WB3R;lq?9KjvtpF9k^-4ORz2DH6^H^nVX+raEkZmj>C3B>|x<$~*5O-t*>Lr>&`T zFS#)(xqJ05GJN~*Yl)fL;qenPyafm&1F*2wyMG8_ z;peO8sTwdXaMGl^)_i2E_m|3bb)Wt<9p;xA&~}E#rs~bBWL{Y%N{kd_hg{!wKWZFO zT1aJ(HlIW2$tc+e=}DyL#J!ICI;ZK-qSX2yKdKLRp8cD<;|n7=b8V>`T~}tN=U$_& zoWaOc#0`AY@HsDbB7?O8Z>O;1wH@|5i%woD=Kla0)lAnmFH80S00007xl49EXhb>az-D#YA@$pgweRFU!qlpzxn zb0mb6nTaU_=^I=X0^31Ik(z|64iPI^}s2}#5hNKzKgd&CM5EN9AldoRMq%($KdfKFo(B-bUP!d@eQG6#7+ z!^PT2hV!*`bgckV5lXQ48@2=FMe)_|9c49+{%FCQxG zXQnsY0RZM-Q-3u`GDA^RZJqqnlOuczQLqANcdNVv21M`<6QcnY0;V_IVKv^EIi?E0 z34-V{nEyW`*|`YN7yG`es|L3_C&RsT&Ite7jP`+MNuNP;2i{m1PsRg3`tz-ZC{xjgc4jw@ zc=Ww0x67=IMPtdf_GtRrZ(NxEN5>ZbNayA2whb&z$47?VSuxXa5r9%I&39$5ybyNG6 z6<=>zt{Dik!t(jhrU|x2X-!fnUb?$4xzQA}t;sard^?5NeUQbyK?q!?fz}d38F)-j z<&N4->u-AdniqMBt$*)atiR{sCtiHBbV%Pmzs$J8yfwqP8dN#e>2Fr-AIkxG!|&Eqd0En(%!mj@SRln#FGs<-Cm%_&|}({Sqc zf0=u6>sM-lC9iK183Ff|c{$mCvONBrv{azaev8%`fk2xknTHP2bYLwTS3JVrt1sZ# z;hkK5i9cg_$#|qx1UweWL`UNI$)<15zhdgkUx@&} zUA87zkeBnrtgO(zhRaLZk=@-ym)f=N@un^-2$!4ejVoFA!i{{r-yD85+2o_+`w2TO z7&#_$^KRq(idne5K9qFOfVRBkKJx&F##b;*S3Fr)kbB?!IkTew-vT_np7y7J|TMhY+V4@c47kBc^cA$Me~IVg;tO7@aeXAz2eK>JQLX zmX9GJeyW`{jellVbQE`uycLfX`pXf^bNemdzNYc-j)6_95~cC1`scM}UfAJiKz)9u zy2qpiXw~yyO?$t=(0?deYdkVRseb^R1gRa${F1)42Pyls9tO=tn*trH#R+f2Xx)QK zfIW7^HQ6q+mxjv)M83QQE+shm!Wl13?{)1JWBXqW#^)c?=XTbh#W@f3Fp$Ue@Iuwk zi6x>WPNit7ew|A`OK?NQVj8Ahg7Rk&sy|L!vYqBJW63mw*j_Ki2lr54Sp4yIUmra| zoNaFa%yVzt|A+U*O*6lD|B$@#H$S}N`vfwwDe@1%5GG2~-E{Z4MrnZplL88;slb-H zM>})vD2=Va)?iC;l*W-@Vyrz(WOFs1mRf2j zUPSZIF<31vL_S)}j@XBI-u$x&2{Gr7kN#=l|I-5h`q(Qa_+%YJ2Bft+Mo;wVTqO^r`TFa`-G720C zNz+Z};2s>8AKRPBCw3h#g!WP!i7=zxN5R0$InurtM}n_-9OaW9;2nQ0qcR4t;rPpd zn^=1XTR&UI!hsJ^o;!?mJOP$>h$CFL-Svwl;&TGr|KBSv@C37`r)+S#CerB^ka8Tn zW;Rz3`7xth7qe*fKO*RD1-8=IT4Q%<);{gmN|Q|6Od2we`zEaBp;cG2Z2M11Iq6P;yP8Zp zG!Gcb=JE^{C!glPkO90{e1LZvKcL}Z&7fm~lCaHaV-$62C%e|or|Ix^W{mkaX5F!m z=W_R<+ghnQzKZjjJ$RJ2)3T~F&P-p3L_G16vtr=>XI2jMWMto~O;4Uuo!LZbx-(19 z>|;xtfIpv^gTBM=#&`L+;cYTR0eQiGILbk3kkTRBQ;HK#^WL$C7+lwkH^a@c^ZGLR zhW9zzx18kBJ-80;WZtkx5rd}@&d$L}Cn<>8)U3Iek(=IQRH}%8w}@D;{ushdBzlUv zXbqlt?br?3D;{Mpwh3_A{O?WIhUYdZEOd8p_7I}$ygNXZLTMOLd&&nf#j z1AJ4FhC*tMqZ|elj>9~>otm~o+~!@t#374`2pd}~hKPQM!VzSaO(z`6K{ygeEApKj zma5-jBqX@K>`3n66>~j%YF_5>iCr}D8IfqUk)Iq{e{9Fz9b(Z#ueghfOP&bk6x?bn z5ZxH;dSH>mNx4vq%<|Ba}u&+qOP% zrRmGlTB8ssrIB<(1Ig*MXpnWH2B{6wE_au8G#Y^^JXG|$5GUdA zhfVV+&zpkZlaE5+ap!X=y_Mq7dHBto9@f<;tvW3ZpiNG+AKp3s;Tg0O6 z?2A6h^J6qqKCZ+!_y+7i4kj)vVYmv%&V1Igar+Hr3^r5`bk>D$T&X0Mlqf*@0@PVa zd@_Z*Ly!n$Vo22qA9QD*iRHJDpD~zqjZae6GLEsu*AWT^DDjM?_SjBx2UdXAXTcCH zI&E>RZ5wY?{eas>t|BYY5A9dXneq(1s}ED(x`W_llW5HE1xn$I$B+TPFPMmpHpgAM zaE#^l-lPoIS=zA;i~JKuaqZtuQAdh~Lo3+a{45n=MQJ!q%Cw04GrKjYl)#p0vIBjo z$o@JX)h^{o+eU(cV%%hKQtYQJa6YnI`<-KfNlojAY&`lnmz6(Ae&$eYX`{5laZzSelN}Ae=7a2Z z^v+i}Qe?5)Jc5;R9^O!2QkENiPL^_%1Z`0snoc027n`dd$7KdM*tn8Wz2>2`>Ri2* zMhF)t+V-)!=HHpo=YEPZM(eeQ&`Kkv-FejDGqU+j%S{wyP8Q4S7w@$a$z-98 zi7k6#M@__^#qoY4c+1mDT)&2Qvc<@Z8I10=5U-g<)G#{JQfD}KLDAFBp}^&#$n`ZY z8T3n59av0@S%p?E9MYgQhT)a_=v@A!f za+V&u)4aU*W4Tt^b^>WBkV>6{g*7=DqtR&>!FUlD^?H!_VZ&YCqhk2hfruJF;5eoU@=~i18p!sUCaJc zuThh4VEV>0?zlxLGz!C)K`b31W=FB5pssxz&u{87xaj}c9u8JaKx;{>QB7&-*FglamHN`fFMXOEcf~_zNC+Ghy?S3joBWiZ zSw^lL!|v<{*?;PN;z78mz7MVL-||#$9s`xc|~fXs2*8Fz9T+fFWKTgyF!{1x=hoJ}&F zJmaFLDQvtWX>`Osv1&Zo>8o~b*wFjP@`_Nr7CEhiT{4NCj^i;)Nh{}bB@EpIkp1;q zMW-cf%VJ2)etgZJaOaUamd}i0rb7g>E9hJBEt)&FBI7BPKaXKs9^;ePGG-VHk-h$z z_V_M##~#CLB5V4L2_9W@KAV z+6(%|*jGL6(Al|o5{awG$*cOz0M=B;=f+i^PGsEZTJ9vR3{ zg3Q)NM(=r#T@&V#KJPP5x?4Gw0j9@fSK|-3VMjAsNVKV#w!4FiYlkwZ6~6t>uSq34 zuob*q`deBne#V5rb4W+CrfNKu2mecr8MR=^nX1Hs$*rw*%ZKQW_}5A+SCZ|&4wZX8 zN;=)ZtNeH+6Zfp7F(b(IwLfQY^@oi7_;n5ry_gP{uM4Ym;wgzqAdzI&`o%Pd^668z zj}C8$h^0wI-lx3rDCLd&Ig;N-eNb@ut{{;Tn?v44nnIw{lG2(rtPQQBDDx&v&v3LB zWP7Gi6qrqO>b++++;_tpXE^cQTQqIOFBSL*HrgsnMkWNMqs_6IpIU=CUe+UzYHPTh?i3DYn0VL~}qVu)Olt{faQ zh`>jkdX#;chiS|hk7|F0t&jea4+p}vyLV#Q8T3h(kusBfl$S$=GYxOMO<7cNJf|O8 zY0~lV{$%*X52~NLx$O%DIJo6!2{DwKT>tggXv;A)#U z!V_pu>}PlTouu8(6r1;un=uD%3LKRnVb|e^Ft+L--28iN?=A{sn*2x^L*-q3@6s3p zni~12)CA8I)(xM_h?WXA=Khe(L_aoUKTk66R+JIMNkr4BaQ(eie^{{bZ&s%VE_(S% zcV53c47b0V0-mPfvLiu_>lPCJy#ylQPMJ8KYw_#R6n3m7>9c4u@(B9J(AM@2B4iL&;8NP}T^go~NkJ9g1_R z=8v^+Em`E8d{_O={Q)QK+^53zC017H)rRHif(M=1-3;`?lkAJDwFKb{685z)?~^9H zRuvxQqo~8fb0e?7(!&U5UjZ7-Ko&=QmywJ#lapUa$&tmJ==&4u3#Wn*U0gyVv_v=# z7!VFdQLzO&8XO{2OYM8iE02n2P2+kx4Lbox5Q0cwv|b zyfiwC$S@Y-GropKaqYehyfo+@%EBoY?hEqrh>MY)MI6g2=o-L9(%DRt@jdz&yHVI@ zZ|j@`OEeCy#7r_%-zVC-Y;AQ;`!{)}A^s2TQWnhp{R=r+eXof->%9$uZRERug)$5- zIkb^+pFK?fsOHieqi}K(#i1oA)q;5%!3sAq^Hr47LXeyJf=!k)C}5#?tu+rAV7@(y0WFrxwF}5m)_qeEHu* z>vT6a&@w^TeKWz>9k{*ce<6zy2r&I58egQt`{bd5$eM?nUc2Twov!# zy&5R#;Ivjd31``VnXN^4NB(l}24v(*eR}Yv1pr7Kr@h?ttv^6|pyh4G=*@dgsu4JM`Xr?_H!x5ew245s=h2=Bj(`wbz>8JPgCf%w?7?Wk_yi4EP!52*WU2 zw@$_HQhExd?cYBg7h{-9s~Bb{=};Dxm`W${sek-0)E05QIf5n4+6#Jb>ht&2>ntp( z&=BJ8VHklwszg(6n^~UGS|rIS!q1sOm(?l+SuR1JvQAlOu)^=dI}DZiSxxIymdCN}F9rqNNC@+v5O6Jifpd zdm*S8?1zf|GGsYzN2rr14%w`Pl)^1|E15voavwa5PT+~3=UU^2$1ZecnII$jChDoqk!%a}rkbEIK?Mt}=k@mF zIcE(OxS}J&8~4K8@hmKZCyaWdy$6@$!EC!xL!#YX^gAb!IS{Z}*L?`&i>)?i38svg6AST2Q5m_2Y z%{0ddm6^P<&_+_OKlJ^KG2ZYfb9UL8 zaPNyp2IK8DnCz&=SKUwH?OzHBJrBg*cR}Pm2XwU-BHX8qGo$}8S^S_#u={0;<>T^~ z*{YG|&FW5Z&EJkRXZtU;g6QVdxwf`-)sJU3g8Hj5SLBKVjI zBfxwSI?Pv~jfds5zb;3!$#R&eF09>lXYP@IHolMLrz&lXGgTG)QO{%v1{_ww2eUkSB~2tZ?hPU_FK?sE{-FnpJB;0E$p~#hz8DawA*jSE88ttZZj9{ z)?3j@dhK=uR!$?I@^5i=KwM?R{TdC1|6^^=PAlPT%WHSqfe!8tu(Fyf3N?%6&~sRV zYqu^z^@;^f9FIV?wJ0W?ci~&7Jy3F4jIEr7kXOEhey3d+aQzH@E}x;3%H}$42IIzn zYqk_+hFeNzxAkH8uHp8;HkZ%Q>9&{fIR@PKBHn5<_}m#RG1>qLi}|p#UJWgq?Xa<1 z17&*Na@?gjz}W&uXD>3$524ib0vzsKLZH4hnjF4BHuYze=lxYK#h_LUVab z9+P3G&>e6VO`ca^bUhIE8XPPUy^H;O^3dsb0p0#*(MS1x{^xK;#uj&ET~T1J0|kfm zSgZR57SY@@&ioLQRRq8G0nELkhj|ABu)}CKntV=U!2b;Teb3@BXE|?wVB{GA7pue7 z;&i^*@30ncLaw1Fz;u`uR>08T-vuW?6HQ*-Hl^k&NLJ+uayU-hX z6=Kf9P;%Y`3q3vhHeN-Q-&Oc}9f6GVc9aC2MnBcj9em~Qg?8seUWA-KR^eoUSaW-H zM&5+7vnaZvEMYIkG!dLMzQ-yQ^c9K~wdkCZ%j;AP|$D9{;Al)D&e zuA+Dsql`W}d-M{zBIHo!EPbgVNKvIHP8qKvv@o8i23z-os0h1;K01^97F0f-K>EKR zRvF(WYv7dWI>=gz;F#Mg1e#fZFM6lC?2N{rsHXlf;O#DD>4qp1*v0W#FCUfiwdQ zq)wrq!sk4<0Qb1)Pt)h6vuRU0Y+N7xEK;U0Oy#meWw6g-HEuZXfH18)_t29tb&!N! z;689X4?@9h2d;aI!rbjJa^kLGgWG&;(A*0%XNl6Mp_)m9S!Q&uH05D}&Z;N8H)Dh4 zBGk~>2HEt?8JJ)og9RHmnaWEyfojlR=msCgaJm^%B4uIgCyB`{3(_-2f2J`ysQ;bm zhA0kDf?dD~(%%PuI|j?Ggi0IYO#BA#+F~Hr219qPP#@!g-MTk%$m$?OID2v1{Ro;9 z?Rj~FIo4n?kYk0B99ulgFu+yrF07|-)OYzVlt<}QPa-|TYwkNSJgqyBV@YRctLc1e zyv}lksP$&Za1W)wOtn)P$aBKbJtqwEz(uxmIEp<}plEj$ajp@li4MX@fdl0`VwiMB z^0`QiSHv|JaXia4g+tf=Zwk9no;!x=ygo?h_3g&1k;Se- zsVwB>K=Edx%V zJbtK-!W}DPc)NyCU!w5taVQMEb-^4nhtiz_)ZKF`J;~`(OnXYT~<3$eAf+&HRz17xt8v) zHQ4R8A1jQGBE>5W14RiCcin-+9DTTkSYqr^Bt{;FWBh3%o+Z1<&wK;XIL357OdK4g zbQZ&v33ykVf#@tl+zgdO@8f7p(j3g>k3CI5+x;{&7pCEPK|CCz3~<0o0_ho^Fp9g1 zp0Y$FCpkb&R}R6nKYaB#1sA>cVS?%&sfM}7>mj-2@ zb986BiN8H7#At2$6lzG;q)|8xW0W>tmx|8vY&66-Le^IivYyvbQ{jcwbT5b~SwleX zJif2Hhi{(UrRQ@S7Cr_Ts=W7)rjo>iGwsfn-H)@~@(X>Smv9x;RcOVYM^?ZK?2xxcUR)U#UNlCK?JJDc=OVzp5a)H`km6e# zH@nRb!^+{;3y15AF#cjT3V)5$J#_p9#TyGTL2|OG0N=Mff_l$u?Fwsom577MZF)HuY z;lEyWK_WsNj1`0HVdo%irvtN0MQDX6g5k^o*C!nnIaPN9-OB_&Z14BtZ8i7ZCOT?= znry4YJQ0@HVPAlUp_@_cr^shIYG{!gR6A5k_g=gmjpv}yts$a)<^iZ?*Z%_ z>VM8iC=d9(cK#^+MPyIX*raBMr zx*PGjvlb7llW~n~E}r>T=xBUAIMG(R_mA56l)TQD)vCjtjWvU9t$*okYQ;cHGwwc( z2cL`{L<)Rrz4+-gP&*f382rRAr~iXt zw*0^_OC}gbkVP%S%w^$5W`x;bKKPrR$A)XC%S}wz!`8{x&9=d|#cPw=X6+RF2^xey zvQs$fnlt|!5S3$A+&DAme8gpbgA_S_uhbj-u|6{VsdNKL*OQ+cn<>Zd9eIV{z(SJ$ zocqN&%lLaOW-$N9=lb)1C{dmNO@_k!I#7^?%Dy>=-BfBuVNJaR+ zo9OJ_W4ai+HiB@mSb$y%x0x)$D?$rF+guQPxpPs=+IFVX+ex;YF2YMHo3AYNKM6M$ z#wN%w*u>~De1E1de^!@~Sh3me!V%v%`Q2pGS%yx_!{(`6`DU-I9llm$G_T%RZMXZ!Uj`s#<} zHH9wiAGE$rb_|=;YSQ- zDcUK{qRn#EdtlQBsZJNQMOdoGH_)uKMsw3VzB!-LuTRlQR9c-?X|VH02c6A0Yc>z< zHXG1sw+`X5npnR#3hP83LfC`BB|`>Z*{>%%*jlnXZQ!AoblvQi!q|E-I#^rS@4;pr zx-8b?qSbt8YcBZDVvQ9^KC+DPr}Xdlbi!}0Tb!-2u7$OQb=YskfV~J#SuaG2?HY7b zoVAOEU9pBBwaaK6gYcm^$ZMR&WBn6kFWbyR51lb%=~)Tb@S(?UD=)2MI&Vg@x@?$5 ztKB9nC3~E!{(kIG*!EZqkbBz#41pzeHERg-$7-&NH%apu!7!U75ydDzn!SF-A;Bu zQOf^p8m#VAxQirXz+jstKfbgULY&sR=NZ}?{?r&UHAEH{8Ez|VcG!VVvITZH??eZ8 z3KL{2yKcJ_(&mfFHnaq1iT65pO&MBpTDU4>2>J6KxNAXUB^%=)l^vveI!Leo z_#g!P8o!07MB<}YP1;B)|WR;LlGD}@A=i^w#*gi;RK0UZyZ zk9aS}mBAvrWmu%K59#_>(Bilg_w+@Rq}TEP(|4Lt=2LER+=njW_qyEoqmyK(`vG)& z?8g|{91I**VxNf+__=~myLl6qI)|}RXD-g!EkO~@U7N=~G`N3`IyZ3?P`rq2SLLp| zpleLFRHudDH{A>=U2$aT$U};3titpx)~ZS)OhX;RK08sQqr$VX8R(vcpy@(XP+wTP z?K6Av|IE?buK7o69(FfYFdBUS822H2B-vTJya?0snd5n+T3o_bof9eESTeWF! zoCIKYArg|BQaG=79Ic*YH}*P;ZnE(Mu)8Vh+gATf5u(~~j5&zR@_dNz} z{aaXXyBN%&FdVyTiZUxD$Pg#8$8aAQ?L81QUXGROJ0R#j2Y#e$d)ppMbSZB~E)El? z!moaiY=t{fXd_E=DM_~P6X^9jff~o7|J`GDa?{K+aMq`e2hkB#n~7$0=$$+%4=vii zM?=n`C*T~q1E+A$OdnR)!w_d=fa8bbv3A{aY};IhdRKY$1fC(=HmiS@XXEap_$$wA zIDRS?*2?y9P~xJ7s|a&0?TzNbIH*fD%iCnn*FFM17d{AIy8=Fa2{5W;?^lt6z}{G_ zIuLL8M5D>!C2sV)O$-3zr8MYcK;b=X1l44SpO>LIf&9X#aidN_&Sue z1y9?xNp=N&iOxW2WSg4emERQ@Tuett;3aeiT_XGUujrl*_Xb}?wF}GPdts37p5KH? zV;k*Pi`@i}>3MB@oP#?$BL9OV4)5H`&VQJVq^vVX4FbyRkz!;EHJ42YX8DgWvU!A(jhw*B zp3p1k3zz1F2Z-xu<5THu9-BUuH&AyU&h!kN1u$3pI2c(qxZLtVwW})a16nY7J7KiflOQKA%C%aS>#kHlfw~Jh&Q;*rIS58an4t z9eEl-{`(>4y$(9QB4`Sc#(0D*k7wu$r}y9GQa#)MLhcpe7r|c+By)V=q34P!PhHf~ z981}5L>0|>AGOoV@&Z6b4B@g7(C#R$I{;L;asl|5dUa z%8dR8d`jGOe72n{m)%6~yUIkZ9>f^SuG9>02D^cL}K!A55Sz z$K9qfYPdu^={!BUf6{s#n#Iv{M=Sk!-$UN8%=3m;SE3dMSi5y1aVR|QL=$asDv3!6{DIImnW5XoLH-;xE{B^P(7+U)yDVjL!xrVq)20He8 zu*_5dMy|x+#i$YQ9tUXmE3ygr_f59{Zn^IrJ9crxWvdo$?cg>^7Q z^*#-`h1KRlsE<&_XC6y`_YX~B0;9DfA`A=l9yp@O$*hImaj-bvzE z-VjEqj$6ci?DJWMqqkMyZQ+1GUx}CkHwB-;3=Z)~hVNmJ`rk%<6?0#XzY$+DnrTG5 z6U#SE>Gl7jKg~h0dDI@O)6Yu640ko2ZUi^~Q#j_b0iRp1g09;EI$zF%vHxL&MO=i7 z`*Gp{#i1U!7wTSnVMP4(LB};X;<*loZPr4MyB{%emtaZzt{{D*7@ZYRv_B3_?w+(l zPbKdm*8hpPgAei7Tsy3AT!;A5qCSxt7|H6AeZI!e&q#OZg7yE z|3rot)>>|%{nhZNWu_~<8sg1Qv}ZZ;xHy)NW5M!yqlI>O6cT|TlW^p4Ght;yXLHlz zaJ2PAic=cuVu{PjwgHW$UAH&FGBe+hVf7p7=#uf*l&;y%1y+j+#i{A0yoK3>woMSGQ(y zi36nhESLrxCUoU^qCL}x;Kj=;OR%N&t&5h%aR2+hR}T(w=$7 zM-*1%NAWV#8edTwH%bcbzT_V{qswxaY#ClTYMautX}xc-U4q9c9E=ybVwC#wuG9_n zp~(n#_QZ=g;unh?i7#~|p3@Tpg>FBjadpqvrnw3?=eYL|Q#(Tho-AU+EbsZN9J%j~ z%9u#J%JiS+Ln)u9!*Zf5JmDIA1p;L2EK1hr@u4g?`i3~l%k=J+XLER5DVz2&j8ggX zG!FQPldR4#!;>UavJ;479(|kVIL*h7>)tf?!Ng~}^0?HtT#tA8-nUoW^VOU8Jl!>R znDvP)@gaVbP<-UPTw2GSGl*J9+(H>f`185rwx-FC$5#{m2c5K|FX}1$BYQ8{%XwJif$c?q&#S(S4cjS7K(z@YRE4OjbnDH^~UhjgtuXOh!v~BE}yD;SJSm z8KQ|TN_W5<@y1p8LKFlR;2qWVj_Pl_=YWSdlL_y_CskJs-s(wUG5zgOvScXouZG`aLVWC7*!wxCCs| zQ-zL=7v`z%#2D+VK>d8zkOlu_6*_NjLhkdR zc^-Nnra&+G3U*s=MFs7r<8|2>uh03#-+RXI`!|xtKa)02zTuPP7e4T)22=vIo zIp-s&Bmb3_>JU0hFUN726tc&B3+AjTN)n3k)r&NAl;4A$Q63l>RjfIbjd&=8d;RRb{$7}oW`xfLNS4OZyEXP~%BO+#Yj__8@5iZs zA)jPEzHTaoX@(*+>5jtskSx$9zl5{aurcUBRqi7+msFrA_Bm2RAE1-`NJblq@KsA5 zDl!_-@g%Q>sA0ZO?LRxNA0O3k9Bq13J<!+t&Md(^8Cg%@wf7ybVT|zN=*CJL4@!esx?Nl}kWgUIOlszfC}79JXkaeN|2h zu|XB+u6}~PhJps_`{Li5>pw~_PL0{vU0+%<{;G=nEFO~22l;#af{LkdGo{Ud&6^Ih zzioJuNB$5owREm|fgfHq;#&Mk9yh`7G#BTC55bAvPdQID=%rtWUWzPkkv)&GX0T8H zB4VQ-At%13pfEXc%^&sgpXEKd8!O!Uw9sp~wF+-KYsgpRF^y#g))s3*B7VqH9aYi8Emcn{!RBY-tRpo+pF;l==UEJ?evT& z?QK^TD)U>&R`3AKVH=$Ck%ExsE(8`^;|=>ekxteZB?0SPR$;Hp4ir~J^5$i-?J4=M zyue^<%|9B-GH-uMzy7RFNp|?gj^|JECi|MdonU=udYLFac%4l4*PjLH=GDM0;PBvlvbsG-&*@1_wn7R z<$vZq{j+0W^{eh@p6qXHh#Bd6F)-f!0^f|Z;IHG&_{&f;z8!4ByP;YLUMG9cSqDg7 zY(h?637$WBN#kwAo8CrzHPC|B{mppW+ls#qboUoNN{J?$;qm|Let$UDrm6z5>W5A8 z7RLRtdb%S6rhd6dPJ9XLLIa2gNJ89S3TOQdamv*QY3ZGq=zoRbt|s)qdN$D8QWx9X z`b@U&VZnC1#YfKrAGY^@6=#^yd5f065k9WxvwDx!S;@;G7c}$Bk{r_WBfJ*e6!H_p+EZfGb>%`H&LuS%`oJHL|#b0N-9njFwDekNx#ObW#jB`uRf4&Y@CmNi}gp6 z@_6~I&If;P)A9G@AJkXN>VKpk6Kp#5b4JdL^vp5@2@ literal 4150 zcmeHKJ5Iwu5S@^Mh9VLTr7OfGETx2-&~pJ((hw=9;0o^Ca)(GX9DoW5Q4DVxdotR! zcTHj&fjsisZ)V=U*&TnP5H0A0RxA3p+a=K@P?m}RbVl@u*cDtyap47B;7qhe{4W{n zVt3mH?qf})zLrFFZbww}5s<^o|)2zW(@fP5@ zmU#eXWA87_uN&s)Q|9eb68FFl=gc1%4sUREzQfMkdzN9WF`DmJeJKKuhXjFb#iw9UkBvhLU^w5x1qpxhZ;^Vtit>S8ELme diff --git a/src/common/brun.c b/src/common/brun.c index 5f73822b..1d62f4d0 100755 --- a/src/common/brun.c +++ b/src/common/brun.c @@ -1700,7 +1700,12 @@ void sbasic_set_bas_dir(const char *bas_file) { cwd[0] = '\0';; gsb_bas_dir[0] = '\0'; getcwd(cwd, sizeof(cwd) - 1); - + char *ch; + for (ch = cwd; *ch != '\0'; ch++) { + if (*ch == '\\') { + *ch = '/'; + } + } if (bas_file[0] == OS_DIRSEP) { // full path strncat(gsb_bas_dir, bas_file, path_len + 1); @@ -1708,12 +1713,14 @@ void sbasic_set_bas_dir(const char *bas_file) { // relative path // append the non file part of bas_file to cwd strcat(gsb_bas_dir, cwd); - strcat(gsb_bas_dir, "/"); + if (gsb_bas_dir[strlen(gsb_bas_dir) - 1] != '/') { + strcat(gsb_bas_dir, "/"); + } strncat(gsb_bas_dir, bas_file, path_len + 1); } else { // in current dir strcat(gsb_bas_dir, cwd); - if (!(cwd[0] == '/' && cwd[1] == '\0')) { + if (gsb_bas_dir[strlen(gsb_bas_dir) - 1] != '/') { strcat(gsb_bas_dir, "/"); } } diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 692d03ad..3b74be3d 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -702,6 +702,23 @@ char *Runtime::getClipboardText() { return result; } +// +// System platform methods +// +bool System::getPen3() { + bool result = false; + if (_touchX != -1 && _touchY != -1) { + result = true; + } else { + // get mouse + processEvents(0); + if (_touchX != -1 && _touchY != -1) { + result = true; + } + } + return result; +} + // // ma event handling // diff --git a/src/platform/sdl/Makefile.am b/src/platform/sdl/Makefile.am index cfa57b7b..7de2115b 100644 --- a/src/platform/sdl/Makefile.am +++ b/src/platform/sdl/Makefile.am @@ -1,5 +1,5 @@ # SmallBASIC for SDL -# Copyright(C) 2001-2014 Chris Warren-Smith. +# Copyright(C) 2001-2015 Chris Warren-Smith. # # This program is distributed under the terms of the GPL v2.0 or later # Download the GNU Public License (GPL) from www.gnu.org @@ -7,10 +7,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src -I. @PACKAGE_CFLAGS@ -EXTRA_DIST = \ - fixedfont.xpm \ - sbasic.nsi \ - welcome.bas +EXTRA_DIST = $(desktopentry_DATA) bin_PROGRAMS = sbasicg @@ -36,6 +33,11 @@ sbasicg_LDADD = -L$(top_srcdir)/src/common -lsb_common @PACKAGE_LIBS@ sbasicg_DEPENDENCIES = $(top_srcdir)/src/common/libsb_common.a +iconsdir = $(datadir)/icons/hicolor/48x48/apps +icons_DATA = ../../../images/sb-desktop-48x48.png +desktopdir = $(datadir)/applications +desktop_DATA = smallbasic.desktop + if WITH_WIN32 sbasicg_LDADD += win.res sbasicg_DEPENDENCIES += win.res diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 630b9631..9c48d7dd 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -504,7 +504,7 @@ void Runtime::pollEvents(bool blocking) { maEvent = new MAEvent(); maEvent->type = EVENT_TYPE_KEY_PRESSED; maEvent->key = ev.wheel.y == 1 ? SDLK_UP : SDLK_DOWN; - maEvent->nativeKey = 0; + maEvent->nativeKey = KMOD_CTRL; } break; } @@ -696,6 +696,14 @@ char *Runtime::getClipboardText() { return result; } +// +// System platform methods +// +bool System::getPen3() { + SDL_PumpEvents(); + return (SDL_BUTTON(SDL_BUTTON_LEFT) && SDL_GetMouseState(&_touchCurX, &_touchCurY)); +} + // // ma event handling // diff --git a/src/platform/fltk/smallbasic.desktop b/src/platform/sdl/smallbasic.desktop similarity index 65% rename from src/platform/fltk/smallbasic.desktop rename to src/platform/sdl/smallbasic.desktop index d4db057d..f122f865 100644 --- a/src/platform/fltk/smallbasic.desktop +++ b/src/platform/sdl/smallbasic.desktop @@ -1,11 +1,11 @@ [Desktop Entry] +Encoding=UTF-8 Name=SmallBASIC Comment=SmallBASIC -Exec=sbasici -Icon=/usr/share/icons/hicolor/32x32/apps/sb-desktop-32x32.png +Exec=sbasicg +Icon=sb-desktop-48x48.png Terminal=false Type=Application Categories=Application;Development; MimeType=application/bas - - +NoDisplay=false diff --git a/src/platform/sdl/syswm.cpp b/src/platform/sdl/syswm.cpp index 0173ff97..48290e42 100644 --- a/src/platform/sdl/syswm.cpp +++ b/src/platform/sdl/syswm.cpp @@ -28,7 +28,8 @@ void loadIcon(SDL_Window *window) { SDL_VERSION(&wminfo.version); if (SDL_GetWindowWMInfo(window, &wminfo) == 1) { HWND hwnd = wminfo.info.win.window; - ::SetClassLong(hwnd, GCL_HICON, reinterpret_cast(icon)); + ::SendMessage(hwnd, WM_SETICON, 0, reinterpret_cast(icon)); + ::SendMessage(hwnd, WM_SETICON, 1, reinterpret_cast(icon)); } } } diff --git a/src/ui/editor.cpp b/src/ui/editor.cpp index 4ef2d549..5e2cade1 100644 --- a/src/ui/editor.cpp +++ b/src/ui/editor.cpp @@ -50,7 +50,7 @@ void System::editSource(strlib::String &loadPath) { editWidget->updateUI(NULL, NULL); editWidget->setLineNumbers(); - editWidget->setFocus(); + editWidget->setFocus(true); if (strcmp(gsb_last_file, loadPath.c_str()) == 0) { editWidget->setCursorRow(gsb_last_line - 1); } @@ -221,6 +221,10 @@ void System::editSource(strlib::String &loadPath) { dirty = !editWidget->isDirty(); } } + + helpWidget->setFocus(widget == helpWidget); + editWidget->setFocus(widget == editWidget); + if (editWidget->isDirty() && !dirty) { _output->setStatus(dirtyFile); } else if (!editWidget->isDirty() && dirty) { diff --git a/src/ui/inputs.cpp b/src/ui/inputs.cpp index b6a1b97a..c9412f50 100644 --- a/src/ui/inputs.cpp +++ b/src/ui/inputs.cpp @@ -335,10 +335,10 @@ bool FormInput::hasFocus() const { return (focusInput == this); } -void FormInput::setFocus() { +void FormInput::setFocus(bool focus) { if (!isNoFocus()) { - if (focusInput != this) { - focusInput = this; + if (focus == (focusInput != this)) { + focusInput = focus ? this : NULL; g_system->getOutput()->setDirty(); } } @@ -458,11 +458,11 @@ int FormEditInput::getControlKey(int key) { return result; } -void FormEditInput::setFocus() { +void FormEditInput::setFocus(bool focus) { if (!isNoFocus()) { - if (focusInput != this) { - focusInput = this; - focusEdit = this; + if (focus == (focusInput != this)) { + focusInput = focus ? this : NULL; + focusEdit = focus ? this : NULL; g_system->getOutput()->setDirty(); } } diff --git a/src/ui/inputs.h b/src/ui/inputs.h index cd3c41ce..c1bc4ebf 100644 --- a/src/ui/inputs.h +++ b/src/ui/inputs.h @@ -120,7 +120,7 @@ struct FormInput : public Shape { virtual void clicked(int x, int y, bool pressed); virtual bool isDrawTop() { return false; } virtual bool hasHover() { return false; } - virtual void setFocus(); + virtual void setFocus(bool focus); virtual void resize(int w, int h) {} void construct(var_p_t form, var_p_t field, int id); @@ -212,7 +212,7 @@ struct FormEditInput : public FormInput { virtual char *copy(bool cut) = 0; virtual void paste(const char *text) = 0; virtual void selectAll() = 0; - void setFocus(); + void setFocus(bool focus); int getControlKey(int key); bool getControlMode() const { return _controlMode; } void setControlMode(bool cursorMode) { _controlMode = cursorMode; } diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 1ac5a10b..ddaf2cae 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -126,15 +126,7 @@ int System::getPen(int code) { // fallthru case 3: // returns true if the pen is down (and save curpos) - if (_touchX != -1 && _touchY != -1) { - result = 1; - } else { - // get mouse - processEvents(0); - if (_touchX != -1 && _touchY != -1) { - result = 1; - } - } + result = getPen3(); break; case 1: // last pen-down x @@ -170,7 +162,7 @@ char *System::getText(char *dest, int maxSize) { int charWidth = _output->getCharWidth(); FormInput *widget = new FormLineInput(NULL, maxSize, true, x, y, w, h); - widget->setFocus(); + widget->setFocus(true); _output->addInput(widget); _output->redraw(); _state = kModalState; diff --git a/src/ui/system.h b/src/ui/system.h index 5df684dc..9eb4239d 100755 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -88,6 +88,9 @@ struct System { void waitForBack(); AnsiWidget *_output; + // virtual: + bool getPen3(); + enum { kInitState = 0,// thread not active kActiveState, // thread activated diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 5be7d265..b9cf5b99 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -708,22 +708,25 @@ bool TextEditInput::updateUI(var_p_t form, var_p_t field) { } bool TextEditInput::selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw) { - if (pt.x < _marginWidth) { - int size = abs(pt.y - _ptY); - int minSize = _charHeight / 4; - if (_ptY == -1) { - _ptY = pt.y; - } else if (size > minSize) { - lineNavigate(pt.y < _ptY); + bool focus = hasFocus(); + if (focus) { + if (pt.x < _marginWidth) { + int size = abs(pt.y - _ptY); + int minSize = _charHeight / 4; + if (_ptY == -1) { + _ptY = pt.y; + } else if (size > minSize) { + lineNavigate(pt.y < _ptY); + redraw = true; + _ptY = pt.y; + } + } else { + stb_textedit_drag(&_buf, &_state, pt.x - _marginWidth, + pt.y + scrollY + (_scroll * _charHeight)); redraw = true; - _ptY = pt.y; } - } else { - stb_textedit_drag(&_buf, &_state, pt.x - _marginWidth, - pt.y + scrollY + (_scroll * _charHeight)); - redraw = true; } - return 1; + return focus; } char *TextEditInput::copy(bool cut) { From 227efe045b9a5f61d678d75ac3f5290e7b35b0d6 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 21 Sep 2015 20:14:09 +1000 Subject: [PATCH 05/30] SDL: update icon --- images/sb-desktop-128x128.png | Bin 0 -> 30061 bytes images/sb-desktop-64x64.png | Bin 7231 -> 9819 bytes src/platform/android/jni/main.cpp | 7 +------ src/platform/android/jni/runtime.cpp | 1 + src/platform/sdl/Makefile.am | 4 ++-- src/platform/sdl/smallbasic.desktop | 2 +- 6 files changed, 5 insertions(+), 9 deletions(-) create mode 100644 images/sb-desktop-128x128.png diff --git a/images/sb-desktop-128x128.png b/images/sb-desktop-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..5ff6e8b1c7e25aaced9f0070ae5598aca3a2d274 GIT binary patch literal 30061 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

_W{zo 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 - do { - runtime->pollEvents(true); - } - while (app->destroyRequested != 0); - delete runtime; logLeaving(); diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 3b74be3d..8309284c 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -93,6 +93,7 @@ void handleCommand(android_app *app, int32_t cmd) { } break; case APP_CMD_LOST_FOCUS: + // display menu or exit break; } } diff --git a/src/platform/sdl/Makefile.am b/src/platform/sdl/Makefile.am index 7de2115b..b0e9a017 100644 --- a/src/platform/sdl/Makefile.am +++ b/src/platform/sdl/Makefile.am @@ -33,8 +33,8 @@ sbasicg_LDADD = -L$(top_srcdir)/src/common -lsb_common @PACKAGE_LIBS@ sbasicg_DEPENDENCIES = $(top_srcdir)/src/common/libsb_common.a -iconsdir = $(datadir)/icons/hicolor/48x48/apps -icons_DATA = ../../../images/sb-desktop-48x48.png +iconsdir = $(datadir)/icons/hicolor/128x128/apps +icons_DATA = ../../../images/sb-desktop-128x128.png desktopdir = $(datadir)/applications desktop_DATA = smallbasic.desktop diff --git a/src/platform/sdl/smallbasic.desktop b/src/platform/sdl/smallbasic.desktop index f122f865..441680d6 100644 --- a/src/platform/sdl/smallbasic.desktop +++ b/src/platform/sdl/smallbasic.desktop @@ -3,7 +3,7 @@ Encoding=UTF-8 Name=SmallBASIC Comment=SmallBASIC Exec=sbasicg -Icon=sb-desktop-48x48.png +Icon=sb-desktop-128x128.png Terminal=false Type=Application Categories=Application;Development; From 133846cdb9bdb9c8ae55276a8d20c4601eaf84cb Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 24 Sep 2015 07:22:34 +1000 Subject: [PATCH 06/30] UI: context menu edit completion --- src/platform/android/jni/Android.mk | 1 - src/platform/android/jni/runtime.cpp | 165 ++++++++++++++++++ src/platform/android/jni/runtime.h | 1 + .../sourceforge/smallbasic/MainActivity.java | 10 ++ src/platform/sdl/Makefile.am | 2 +- src/{ui => platform/sdl}/editor.cpp | 21 +-- src/platform/sdl/runtime.cpp | 6 + src/ui/inputs.h | 7 +- src/ui/system.cpp | 51 +++++- src/ui/system.h | 4 +- src/ui/textedit.cpp | 37 ++++ src/ui/textedit.h | 2 + 12 files changed, 282 insertions(+), 25 deletions(-) rename src/{ui => platform/sdl}/editor.cpp (94%) diff --git a/src/platform/android/jni/Android.mk b/src/platform/android/jni/Android.mk index 6e4643ac..3d3919ea 100644 --- a/src/platform/android/jni/Android.mk +++ b/src/platform/android/jni/Android.mk @@ -31,7 +31,6 @@ LOCAL_SRC_FILES := main.cpp \ ../../../ui/textedit.cpp \ ../../../ui/strlib.cpp \ ../../../ui/graphics.cpp \ - ../../../ui/editor.cpp \ ../../../ui/system.cpp LOCAL_LDLIBS := -llog -landroid -ljnigraphics LOCAL_STATIC_LIBRARIES := sb_common freetype android_native_app_glue diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 8309284c..03fc9a15 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -193,6 +193,21 @@ void Runtime::alert(const char *title, const char *message) { _app->activity->vm->DetachCurrentThread(); } +void Runtime::alert(const char *title, int duration) { + logEntered(); + + JNIEnv *env; + _app->activity->vm->AttachCurrentThread(&env, NULL); + jstring titleString = env->NewStringUTF(title); + jclass clazz = env->GetObjectClass(_app->activity->clazz); + jmethodID method = env->GetMethodID(clazz, "showToast", + "(Ljava/lang/String;I)V"); + env->CallVoidMethod(_app->activity->clazz, method, titleString, duration); + env->DeleteLocalRef(clazz); + env->DeleteLocalRef(titleString); + _app->activity->vm->DetachCurrentThread(); +} + int Runtime::ask(const char *title, const char *prompt, bool cancel) { JNIEnv *env; _app->activity->vm->AttachCurrentThread(&env, NULL); @@ -720,6 +735,156 @@ bool System::getPen3() { return result; } +void System::completeKeyword(int index) { + if (get_focus_edit() && isEditing()) { + get_focus_edit()->completeKeyword(index); + } +} + +void System::editSource(strlib::String &loadPath) { + logEntered(); + + strlib::String fileName; + int i = loadPath.lastIndexOf('/', 0); + if (i != -1) { + fileName = loadPath.substring(i + 1); + } else { + fileName = loadPath; + } + + strlib::String dirtyFile; + dirtyFile.append(" * "); + dirtyFile.append(fileName); + strlib::String cleanFile; + cleanFile.append(" - "); + cleanFile.append(fileName); + + int w = _output->getWidth(); + int h = _output->getHeight(); + int charWidth = _output->getCharWidth(); + int charHeight = _output->getCharHeight(); + int prevScreenId = _output->selectScreen(SOURCE_SCREEN); + TextEditInput *editWidget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); + TextEditHelpWidget *helpWidget = new TextEditHelpWidget(editWidget, charWidth, charHeight); + TextEditInput *widget = editWidget; + _modifiedTime = getModifiedTime(); + + editWidget->updateUI(NULL, NULL); + editWidget->setLineNumbers(); + editWidget->setFocus(true); + if (strcmp(gsb_last_file, loadPath.c_str()) == 0) { + editWidget->setCursorRow(gsb_last_line - 1); + } + if (gsb_last_error && !isBack()) { + editWidget->setCursorRow(gsb_last_line - 1); + runtime->alert(gsb_last_errmsg); + } + _srcRendered = false; + _output->clearScreen(); + _output->addInput(editWidget); + _output->addInput(helpWidget); + _output->setStatus(cleanFile); + _output->redraw(); + _state = kEditState; + + maShowVirtualKeyboard(); + showCursor(kIBeam); + + while (_state == kEditState) { + MAEvent event = getNextEvent(); + if (event.type == EVENT_TYPE_KEY_PRESSED && _userScreenId == -1) { + dev_clrkb(); + int sw = _output->getScreenWidth(); + bool redraw = true; + bool dirty = editWidget->isDirty(); + char *text; + + switch (event.key) { + case SB_KEY_MENU: + redraw = false; + break; + case SB_KEY_F(9): + _state = kRunState; + if (editWidget->isDirty()) { + saveFile(editWidget, loadPath); + } + break; + case SB_KEY_CTRL('s'): + saveFile(editWidget, loadPath); + break; + case SB_KEY_CTRL('c'): + case SB_KEY_CTRL('x'): + text = widget->copy(event.key == (int)SB_KEY_CTRL('x')); + if (text) { + setClipboardText(text); + free(text); + } + break; + case SB_KEY_CTRL('v'): + text = getClipboardText(); + widget->paste(text); + free(text); + break; + case SB_KEY_CTRL('o'): + _output->selectScreen(USER_SCREEN1); + showCompletion(true); + _output->redraw(); + _state = kActiveState; + waitForBack(); + maShowVirtualKeyboard(); + _output->selectScreen(SOURCE_SCREEN); + _state = kEditState; + break; + default: + redraw = widget->edit(event.key, sw, charWidth); + break; + } + if (isBack() && widget == helpWidget) { + widget = editWidget; + helpWidget->hide(); + redraw = true; + dirty = !editWidget->isDirty(); + } + helpWidget->setFocus(widget == helpWidget); + editWidget->setFocus(widget == editWidget); + + if (editWidget->isDirty() && !dirty) { + _output->setStatus(dirtyFile); + } else if (!editWidget->isDirty() && dirty) { + _output->setStatus(cleanFile); + } + if (redraw) { + _output->redraw(); + } + } else if (event.type == EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED) { + _output->redraw(); + } + + if (editWidget->isDirty()) { + int choice = -1; + if (isClosing()) { + choice = 0; + } else if (isBack()) { + const char *message = "The current file has not been saved.\n" + "Would you like to save it now?"; + choice = ask("Save changes?", message, isBack()); + } + if (choice == 0) { + editWidget->save(loadPath); + } else if (choice == 2) { + // cancel + _state = kEditState; + } + } + } + + _output->removeInputs(); + if (!isClosing()) { + _output->selectScreen(prevScreenId); + } + logLeaving(); +} + // // ma event handling // diff --git a/src/platform/android/jni/runtime.h b/src/platform/android/jni/runtime.h index 61be38b2..9805c05f 100644 --- a/src/platform/android/jni/runtime.h +++ b/src/platform/android/jni/runtime.h @@ -22,6 +22,7 @@ struct Runtime : public System { virtual ~Runtime(); void alert(const char *title, const char *message); + void alert(const char *title, int duration = 5000); int ask(const char *title, const char *prompt, bool cancel); void clearSoundQueue(); void construct(); diff --git a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java index 66542455..779f967d 100644 --- a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java +++ b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java @@ -56,6 +56,7 @@ import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; +import android.widget.Toast; /** * Extends NativeActivity to provide interface methods for runtime.cpp @@ -300,6 +301,15 @@ public void onClick(DialogInterface dialog, int which) {} }); } + public void showToast(final String message, final int duration) { + final Activity activity = this; + runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(activity, message, duration).show(); + } + }); + } + public void showKeypad(final boolean show) { Log.i(TAG, "showKeypad: " + show); final View view = getWindow().getDecorView(); diff --git a/src/platform/sdl/Makefile.am b/src/platform/sdl/Makefile.am index b0e9a017..a087e5b8 100644 --- a/src/platform/sdl/Makefile.am +++ b/src/platform/sdl/Makefile.am @@ -17,7 +17,6 @@ sbasicg_SOURCES = \ ../../ui/window.cpp \ ../../ui/screen.cpp \ ../../ui/system.cpp \ - ../../ui/editor.cpp \ ../../ui/form.cpp \ ../../ui/inputs.cpp \ ../../ui/textedit.cpp \ @@ -27,6 +26,7 @@ sbasicg_SOURCES = \ display.cpp \ runtime.cpp \ settings.cpp \ + editor.cpp \ syswm.cpp sbasicg_LDADD = -L$(top_srcdir)/src/common -lsb_common @PACKAGE_LIBS@ diff --git a/src/ui/editor.cpp b/src/platform/sdl/editor.cpp similarity index 94% rename from src/ui/editor.cpp rename to src/platform/sdl/editor.cpp index 5e2cade1..09c279fb 100644 --- a/src/ui/editor.cpp +++ b/src/platform/sdl/editor.cpp @@ -12,11 +12,6 @@ #include "ui/system.h" #include "ui/textedit.h" -#define SAVE_FILE() \ - if (!editWidget->save(loadPath)) \ - alert("", "Failed to save file"); \ - else _modifiedTime = getModifiedTime(); - void System::editSource(strlib::String &loadPath) { logEntered(); @@ -68,7 +63,6 @@ void System::editSource(strlib::String &loadPath) { _output->redraw(); _state = kEditState; - maShowVirtualKeyboard(); showCursor(kIBeam); while (_state == kEditState) { @@ -90,13 +84,6 @@ void System::editSource(strlib::String &loadPath) { _modifiedTime = getModifiedTime(); event.key = 0; } - if (editWidget->getControlMode()) { - if (event.key == 'e') { - event.key = SB_KEY_ESCAPE; - } else { - event.key = SB_KEY_CTRL(event.key); - } - } switch (event.key) { case SB_KEY_F(2): @@ -118,11 +105,11 @@ void System::editSource(strlib::String &loadPath) { case SB_KEY_CTRL('r'): _state = kRunState; if (editWidget->isDirty()) { - SAVE_FILE(); + saveFile(editWidget, loadPath); } break; case SB_KEY_CTRL('s'): - SAVE_FILE(); + saveFile(editWidget, loadPath); break; case SB_KEY_CTRL('c'): case SB_KEY_CTRL('x'): @@ -140,7 +127,7 @@ void System::editSource(strlib::String &loadPath) { helpWidget->show(); break; case SB_KEY_F(5): - SAVE_FILE(); + saveFile(editWidget, loadPath); _output->setStatus("Debug. F6=Step, F7=Continue, Esc=Close"); widget = helpWidget; helpWidget->createMessage(); @@ -233,6 +220,8 @@ void System::editSource(strlib::String &loadPath) { if (redraw) { _output->redraw(); } + } else if (event.type == EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED) { + _output->redraw(); } if ((isBack() || isClosing()) && editWidget->isDirty()) { diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 9c48d7dd..237ce423 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -704,6 +704,12 @@ bool System::getPen3() { return (SDL_BUTTON(SDL_BUTTON_LEFT) && SDL_GetMouseState(&_touchCurX, &_touchCurY)); } +void System::completeKeyword(int index) { + if (get_focus_edit() && isEditing()) { + get_focus_edit()->completeKeyword(index); + } +} + // // ma event handling // diff --git a/src/ui/inputs.h b/src/ui/inputs.h index c1bc4ebf..b1804018 100644 --- a/src/ui/inputs.h +++ b/src/ui/inputs.h @@ -212,12 +212,15 @@ struct FormEditInput : public FormInput { virtual char *copy(bool cut) = 0; virtual void paste(const char *text) = 0; virtual void selectAll() = 0; + virtual const char *completeKeyword(int index) = 0; + virtual int getCompletions(StringList *list, int max) = 0; + void setFocus(bool focus); int getControlKey(int key); bool getControlMode() const { return _controlMode; } void setControlMode(bool cursorMode) { _controlMode = cursorMode; } -protected: +protected: bool _controlMode; }; @@ -238,6 +241,8 @@ struct FormLineInput : public FormEditInput { void paste(const char *text); void cut(); void selectAll(); + const char *completeKeyword(int index) { return NULL; } + int getCompletions(StringList *list, int max) { return 0; } private: char *_buffer; diff --git a/src/ui/system.cpp b/src/ui/system.cpp index ddaf2cae..8caf81bd 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -41,6 +41,11 @@ #define MENU_DEBUG 18 #define MENU_OUTPUT 19 #define MENU_SIZE 20 +#define MENU_COMPETION_0 (MENU_SIZE + 1) +#define MENU_COMPETION_1 (MENU_SIZE + 2) +#define MENU_COMPETION_2 (MENU_SIZE + 3) +#define MENU_COMPETION_3 (MENU_SIZE + 4) +#define MAX_COMPLETIONS 4 #define FONT_SCALE_INTERVAL 10 #define FONT_MIN 20 @@ -312,6 +317,18 @@ void System::handleMenu(MAEvent &event) { event.type = EVENT_TYPE_KEY_PRESSED; event.key = SB_KEY_CTRL('o'); break; + case MENU_COMPETION_0: + completeKeyword(0); + break; + case MENU_COMPETION_1: + completeKeyword(1); + break; + case MENU_COMPETION_2: + completeKeyword(2); + break; + case MENU_COMPETION_3: + completeKeyword(3); + break; } if (fontSize != _output->getFontSize()) { @@ -566,6 +583,14 @@ void System::runOnce(const char *startupBas) { } } +void System::saveFile(TextEditInput *edit, strlib::String &path) { + if (!edit->save(path)) { + alert("", "Failed to save file"); + } else { + _modifiedTime = getModifiedTime(); + } +} + void System::setBack() { if (_userScreenId != -1) { // restore user screen @@ -702,7 +727,14 @@ void System::showMenu() { } StringList *items = new StringList(); - _systemMenu = new int[MENU_SIZE]; + int completions = 0; + + if (get_focus_edit() && isEditing()) { + completions = get_focus_edit()->getCompletions(items, MAX_COMPLETIONS); + } + + _systemMenu = new int[MENU_SIZE + completions]; + int index = 0; if (get_focus_edit() != NULL) { if (isEditing()) { @@ -713,8 +745,13 @@ void System::showMenu() { items->add(new String("Paste")); items->add(new String("Save")); items->add(new String("Run")); +#if defined(_SDL) items->add(new String("Debug")); +#endif items->add(new String("Show output")); + for (int i = 0; i < completions; i++) { + _systemMenu[index++] = MENU_COMPETION_0 + i; + } _systemMenu[index++] = MENU_UNDO; _systemMenu[index++] = MENU_REDO; _systemMenu[index++] = MENU_CUT; @@ -722,7 +759,9 @@ void System::showMenu() { _systemMenu[index++] = MENU_PASTE; _systemMenu[index++] = MENU_SAVE; _systemMenu[index++] = MENU_RUN; +#if defined(_SDL) _systemMenu[index++] = MENU_DEBUG; +#endif _systemMenu[index++] = MENU_OUTPUT; } else if (isRunning()) { items->add(new String("Cut")); @@ -738,10 +777,12 @@ void System::showMenu() { #else items->add(new String("Show keypad")); _systemMenu[index++] = MENU_KEYPAD; - bool controlMode = get_focus_edit()->getControlMode(); - sprintf(buffer, "Control Mode [%s]", (controlMode ? "ON" : "OFF")); - items->add(new String(buffer)); - _systemMenu[index++] = MENU_CTRL_MODE; + if (!isEditing()) { + bool controlMode = get_focus_edit()->getControlMode(); + sprintf(buffer, "Control Mode [%s]", (controlMode ? "ON" : "OFF")); + items->add(new String(buffer)); + _systemMenu[index++] = MENU_CTRL_MODE; + } #endif } else { if (_overruns == 0) { diff --git a/src/ui/system.h b/src/ui/system.h index 9eb4239d..a0a12593 100755 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -73,6 +73,7 @@ struct System { void runEdit(const char *startupBas); void runMain(const char *mainBasPath); void runOnce(const char *startupBas); + void saveFile(TextEditInput *edit, strlib::String &path); void setPath(const char *filename); bool setParentPath(); void setDimensions(); @@ -88,8 +89,9 @@ struct System { void waitForBack(); AnsiWidget *_output; - // virtual: + // platform static virtual bool getPen3(); + void completeKeyword(int index); enum { kInitState = 0,// thread not active diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index b9cf5b99..f08dad68 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -292,6 +292,27 @@ void TextEditInput::completeWord(const char *word) { } } +const char *TextEditInput::completeKeyword(int index) { + const char *help = NULL; + char *selection = getWordBeforeCursor(); + if (selection != NULL) { + int len = strlen(selection); + int count = 0; + for (int i = 0; i < keyword_help_len; i++) { + if (strncasecmp(selection, keyword_help[i].keyword, len) == 0 && + count++ == index) { + if (IS_WHITE(_buf._buffer[_state.cursor])) { + completeWord(keyword_help[i].keyword); + } + help = keyword_help[i].help; + break; + } + } + free(selection); + } + return help; +} + void TextEditInput::draw(int x, int y, int w, int h, int chw) { SyntaxState syntax = kReset; StbTexteditRow r; @@ -1016,6 +1037,22 @@ void TextEditInput::findMatchingBrace() { _matchingBrace = pair; } +int TextEditInput::getCompletions(StringList *list, int max) { + int count = 0; + char *selection = getWordBeforeCursor(); + int len = selection != NULL ? strlen(selection) : 0; + if (len > 0) { + for (int i = 0; i < keyword_help_len && count < max; i++) { + if (strncasecmp(selection, keyword_help[i].keyword, len) == 0) { + list->add(keyword_help[i].keyword); + count++; + } + } + } + free(selection); + return count; +} + int TextEditInput::getCursorRow() const { StbTexteditRow r; int len = _buf._len; diff --git a/src/ui/textedit.h b/src/ui/textedit.h index b81060fb..f0af64ff 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -73,6 +73,7 @@ struct TextEditInput : public FormEditInput { void append(const char *text, int len) { _buf.append(text, len); } void completeWord(const char *word); + const char *completeKeyword(int index); void draw(int x, int y, int w, int h, int chw); bool edit(int key, int screenWidth, int charWidth); bool find(const char *word, bool next); @@ -103,6 +104,7 @@ struct TextEditInput : public FormEditInput { void resize(int w, int h) { _width = w; _height = h; } char *getWordBeforeCursor(); bool replaceNext(const char *text); + int getCompletions(StringList *list, int max); protected: enum SyntaxState { From f43f143c2aee573e5cdd345fc239223c327f61cb Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 24 Sep 2015 20:49:23 +1000 Subject: [PATCH 07/30] SDL: fix osx build --- configure.ac | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/configure.ac b/configure.ac index b16625b2..22a7d56c 100644 --- a/configure.ac +++ b/configure.ac @@ -208,6 +208,20 @@ function buildSDL() { AC_DEFINE(_Win32, 1, [Windows build]) ;; + *darwin*) + # OSX Check fontconfig configuration + PKG_CHECK_MODULES(FONTCONFIG, fontconfig >= 2.2) + AC_SUBST(FONTCONFIG_CFLAGS) + AC_SUBST(FONTCONFIG_LIBS) + + PACKAGE_CFLAGS="${PACKAGE_CFLAGS} ${FONTCONFIG_CFLAGS}" + + dnl backlinking support for modules + PACKAGE_LIBS="${PACKAGE_LIBS} -ldl" + PACKAGE_LIBS="${PACKAGE_LIBS} ${FONTCONFIG_LIBS}" + PACKAGE_LIBS="${PACKAGE_LIBS} `sdl2-config --libs` `freetype-config --libs`" + ;; + *) # Unix - Check fontconfig configuration PKG_CHECK_MODULES(FONTCONFIG, fontconfig >= 2.2) From 64a3005080e33e9f7ce18e63494bc246cf60df13 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 26 Sep 2015 16:03:03 +1000 Subject: [PATCH 08/30] UI: added new file option --- documentation/build_kwp.cpp | 2 +- ide/android/assets/main.bas | 38 ++++++++++++++++++++- src/platform/android/jni/runtime.cpp | 50 +++++++++++----------------- src/platform/fltk/Makefile.am | 1 - src/platform/fltk/display.h | 2 +- src/ui/ansiwidget.h | 1 + src/ui/inputs.h | 5 --- src/ui/screen.cpp | 1 + src/ui/screen.h | 2 +- src/ui/system.cpp | 1 + 10 files changed, 62 insertions(+), 41 deletions(-) diff --git a/documentation/build_kwp.cpp b/documentation/build_kwp.cpp index e921e3a5..cd3342f1 100644 --- a/documentation/build_kwp.cpp +++ b/documentation/build_kwp.cpp @@ -236,7 +236,7 @@ int main(int argc, char *argv[]) { } fprintf(stdout, "/* automagicaly generated file */\n"); - fprintf(stdout, "struct KEYWORD_HELP {\n"); + fprintf(stdout, "static struct KEYWORD_HELP {\n"); fprintf(stdout, " const char *package;\n"); fprintf(stdout, " const char *keyword;\n"); fprintf(stdout, " const char *signature;\n"); diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index 73ef8f72..bcd71c44 100644 --- a/ide/android/assets/main.bas +++ b/ide/android/assets/main.bas @@ -81,6 +81,36 @@ sub do_about() cls end +sub do_newfile() + color 3, 0 + cls + print boldOn + "Create new program." + print boldOff + "To enable editing, right click then select Editor [ON]" + print + local valid_file = false + while (!valid_file) + input "Enter file name: ", file + if (leftoflast(file, ".bas") == 0) then + file += ".bas" + endif + try + if (exist(file)) then + print "File " + file + " already exists" + else + dim text + text << "REM SmallBASIC" + text << "REM created: " + date + tsave file, text + valid_file = true + endif + catch e + print "Error creating file: " e + end try + wend + color 7, 0 + cls +end + sub do_setup() color 3, 0 cls @@ -176,13 +206,14 @@ end sub main local basList, dirList, path - local frm, bn_about, bn_online + local frm, bn_about, bn_online, bn_new local do_intro dim basList dim dirList bn_setup = mk_menu("_setup", "Setup", -1) + bn_new = mk_menu("_new", "New", -1) bn_about = mk_menu("_about", "About", -1) bn_online = mk_menu(onlineUrl, "Online", 0) bn_online.isExit = true @@ -193,6 +224,7 @@ sub main if (osname != "SDL") then frm.inputs << bn_setup endif + frm.inputs << bn_new frm.inputs << bn_about if (welcome) then @@ -247,6 +279,10 @@ sub main frm.close() do_setup() frm = make_ui(path, false) + elif frm.value == "_new" then + frm.close() + do_newfile() + frm = make_ui(path, false) elif frm.value == "_back" then frm.close() go_back diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 03fc9a15..8f47c528 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -737,7 +737,10 @@ bool System::getPen3() { void System::completeKeyword(int index) { if (get_focus_edit() && isEditing()) { - get_focus_edit()->completeKeyword(index); + const char *help = get_focus_edit()->completeKeyword(index); + if (help) { + runtime->alert(help); + } } } @@ -764,39 +767,33 @@ void System::editSource(strlib::String &loadPath) { int charWidth = _output->getCharWidth(); int charHeight = _output->getCharHeight(); int prevScreenId = _output->selectScreen(SOURCE_SCREEN); - TextEditInput *editWidget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); - TextEditHelpWidget *helpWidget = new TextEditHelpWidget(editWidget, charWidth, charHeight); - TextEditInput *widget = editWidget; + TextEditInput *widget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); _modifiedTime = getModifiedTime(); - - editWidget->updateUI(NULL, NULL); - editWidget->setLineNumbers(); - editWidget->setFocus(true); + widget->updateUI(NULL, NULL); + widget->setLineNumbers(); + widget->setFocus(true); if (strcmp(gsb_last_file, loadPath.c_str()) == 0) { - editWidget->setCursorRow(gsb_last_line - 1); + widget->setCursorRow(gsb_last_line - 1); } if (gsb_last_error && !isBack()) { - editWidget->setCursorRow(gsb_last_line - 1); + widget->setCursorRow(gsb_last_line - 1); runtime->alert(gsb_last_errmsg); } _srcRendered = false; _output->clearScreen(); - _output->addInput(editWidget); - _output->addInput(helpWidget); + _output->addInput(widget); _output->setStatus(cleanFile); _output->redraw(); _state = kEditState; maShowVirtualKeyboard(); - showCursor(kIBeam); - while (_state == kEditState) { MAEvent event = getNextEvent(); if (event.type == EVENT_TYPE_KEY_PRESSED && _userScreenId == -1) { dev_clrkb(); int sw = _output->getScreenWidth(); bool redraw = true; - bool dirty = editWidget->isDirty(); + bool dirty = widget->isDirty(); char *text; switch (event.key) { @@ -805,12 +802,12 @@ void System::editSource(strlib::String &loadPath) { break; case SB_KEY_F(9): _state = kRunState; - if (editWidget->isDirty()) { - saveFile(editWidget, loadPath); + if (widget->isDirty()) { + saveFile(widget, loadPath); } break; case SB_KEY_CTRL('s'): - saveFile(editWidget, loadPath); + saveFile(widget, loadPath); break; case SB_KEY_CTRL('c'): case SB_KEY_CTRL('x'): @@ -839,18 +836,9 @@ void System::editSource(strlib::String &loadPath) { redraw = widget->edit(event.key, sw, charWidth); break; } - if (isBack() && widget == helpWidget) { - widget = editWidget; - helpWidget->hide(); - redraw = true; - dirty = !editWidget->isDirty(); - } - helpWidget->setFocus(widget == helpWidget); - editWidget->setFocus(widget == editWidget); - - if (editWidget->isDirty() && !dirty) { + if (widget->isDirty() && !dirty) { _output->setStatus(dirtyFile); - } else if (!editWidget->isDirty() && dirty) { + } else if (!widget->isDirty() && dirty) { _output->setStatus(cleanFile); } if (redraw) { @@ -860,7 +848,7 @@ void System::editSource(strlib::String &loadPath) { _output->redraw(); } - if (editWidget->isDirty()) { + if (widget->isDirty()) { int choice = -1; if (isClosing()) { choice = 0; @@ -870,7 +858,7 @@ void System::editSource(strlib::String &loadPath) { choice = ask("Save changes?", message, isBack()); } if (choice == 0) { - editWidget->save(loadPath); + widget->save(loadPath); } else if (choice == 2) { // cancel _state = kEditState; diff --git a/src/platform/fltk/Makefile.am b/src/platform/fltk/Makefile.am index 799d4ee9..87cb1930 100644 --- a/src/platform/fltk/Makefile.am +++ b/src/platform/fltk/Makefile.am @@ -47,7 +47,6 @@ sbasici_DEPENDENCIES = $(top_srcdir)/src/common/libsb_common.a iconsdir = $(datadir)/icons/hicolor/32x32/apps icons_DATA = ../../../images/sb-desktop-32x32.png -desktopentry_DATA = smallbasic.desktop if WITH_WIN32 sbasici_LDADD += sbfltk.res diff --git a/src/platform/fltk/display.h b/src/platform/fltk/display.h index 2bef7e31..921c5818 100755 --- a/src/platform/fltk/display.h +++ b/src/platform/fltk/display.h @@ -44,7 +44,7 @@ struct Canvas { bool _isScreen; }; -class DisplayWidget : public fltk::Widget, IButtonListener { +class DisplayWidget : public fltk::Widget { public: DisplayWidget(int x, int y, int w, int h, int defsize); virtual ~DisplayWidget(); diff --git a/src/ui/ansiwidget.h b/src/ui/ansiwidget.h index 1ee564e3..5fba1e7b 100755 --- a/src/ui/ansiwidget.h +++ b/src/ui/ansiwidget.h @@ -74,6 +74,7 @@ struct AnsiWidget { void removeInputs() { _back->removeInputs(); _activeButton = NULL; } void resetScroll() { _back->resetScroll(); } void reset(); + void resetFont() { _back->reset(_fontSize); _back->updateFont(); } void resize(int width, int height); bool scroll(bool up, bool page); int selectBackScreen(int screenId); diff --git a/src/ui/inputs.h b/src/ui/inputs.h index b1804018..de826f85 100644 --- a/src/ui/inputs.h +++ b/src/ui/inputs.h @@ -73,11 +73,6 @@ namespace form_ui { int get_color(var_p_t value, int def); -struct IButtonListener { - virtual ~IButtonListener() {} - virtual void buttonClicked(const char *action) = 0; -}; - struct IFormWidgetListModel { virtual ~IFormWidgetListModel() {} virtual const char *getTextAt(int index) = 0; diff --git a/src/ui/screen.cpp b/src/ui/screen.cpp index 8b1210de..da46a86a 100644 --- a/src/ui/screen.cpp +++ b/src/ui/screen.cpp @@ -281,6 +281,7 @@ void Screen::removeImage(unsigned imageId) { } void Screen::replaceFont(int type) { + logEntered(); if (_font) { maFontDelete(_font); } diff --git a/src/ui/screen.h b/src/ui/screen.h index 9de4433a..e9e6857e 100755 --- a/src/ui/screen.h +++ b/src/ui/screen.h @@ -109,7 +109,7 @@ struct GraphicScreen : public Screen { void setPixel(int x, int y, int c); void resize(int newWidth, int newHeight, int oldWidth, int oldHeight, int lineHeight); - void updateFont() { replaceFont(); } + void updateFont() { setFont(_bold, _italic, _fontSize); } int getPixel(int x, int y); int getMaxHScroll() { return 0; } diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 8caf81bd..3500f148 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -116,6 +116,7 @@ bool System::execute(const char *bas) { } opt_command[0] = '\0'; + _output->resetFont(); _output->flush(true); return result; } From a6159d9bcded276a3cf1019a6fe65629ba50bca3 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 28 Sep 2015 22:30:38 +1000 Subject: [PATCH 09/30] UI: update help --- src/ui/textedit.cpp | 136 ++++++++++++++++++++++++++++++++------------ src/ui/textedit.h | 6 +- 2 files changed, 104 insertions(+), 38 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index f08dad68..798c4ef3 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -25,6 +25,12 @@ #define INDENT_LEVEL 2 #define HELP_WIDTH 22 #define NUM_THEMES 4 +#define TWISTY1_OPEN "| " +#define TWISTY1_CLOSE "|_" +#define TWISTY2_OPEN " | " +#define TWISTY2_CLOSE " |_" +#define TWISTY1_LEN 2 +#define TWISTY2_LEN 4 int g_themeId = 0; @@ -453,6 +459,18 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } } +void TextEditInput::dragPage(int y, bool &redraw) { + int size = abs(y - _ptY); + int minSize = _charHeight / 4; + if (_ptY == -1) { + _ptY = y; + } else if (size > minSize) { + lineNavigate(y < _ptY); + redraw = true; + _ptY = y; + } +} + void TextEditInput::drawText(int x, int y, const char *str, int length, SyntaxState &state) { int i = 0; @@ -732,15 +750,7 @@ bool TextEditInput::selected(MAPoint2d pt, int scrollX, int scrollY, bool &redra bool focus = hasFocus(); if (focus) { if (pt.x < _marginWidth) { - int size = abs(pt.y - _ptY); - int minSize = _charHeight / 4; - if (_ptY == -1) { - _ptY = pt.y; - } else if (size > minSize) { - lineNavigate(pt.y < _ptY); - redraw = true; - _ptY = pt.y; - } + dragPage(pt.y, redraw); } else { stb_textedit_drag(&_buf, &_state, pt.x - _marginWidth, pt.y + scrollY + (_scroll * _charHeight)); @@ -1411,7 +1421,8 @@ TextEditHelpWidget::TextEditHelpWidget(TextEditInput *editor, int chW, int chH) TextEditInput(NULL, chW, chH, editor->_width - (chW * HELP_WIDTH), editor->_y, chW * HELP_WIDTH, editor->_height), _mode(kNone), - _editor(editor) { + _editor(editor), + _openPackage(NULL) { _theme = new EditTheme(0x73c990, 0x20242a); hide(); } @@ -1423,8 +1434,7 @@ TextEditHelpWidget::~TextEditHelpWidget() { bool TextEditHelpWidget::closeOnEnter() const { return (_mode != kSearch && _mode != kKeyword && - _mode != kKeywordIndex && - _mode != kKeywordPackageIndex); + _mode != kKeywordIndex); } bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { @@ -1480,18 +1490,12 @@ bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { } break; case SB_KEY_ENTER: - char *text; switch (_mode) { case kCompletion: completeWord(_state.cursor); break; case kKeywordIndex: - createPackageIndex(); - break; - case kKeywordPackageIndex: - text = lineText(_state.cursor); - createKeywordHelp(text); - free(text); + toggleKeyword(); break; case kKeyword: _mode = kHelp; @@ -1529,6 +1533,16 @@ void TextEditHelpWidget::completeWord(int pos) { free(text); } +void TextEditHelpWidget::clicked(int x, int y, bool pressed) { + _ptY = -1; + if (pressed) { + stb_textedit_click(&_buf, &_state, 0, y + (_scroll * _charHeight)); + if (_mode == kKeywordIndex && x - _x <= _charWidth * 3) { + toggleKeyword(); + } + } +} + void TextEditHelpWidget::createCompletionHelp() { reset(kCompletion); @@ -1576,11 +1590,11 @@ void TextEditHelpWidget::createKeywordIndex() { } if (!foundKeyword) { reset(kKeywordIndex); - _buf.append("[Help Index]\n"); const char *package = NULL; for (int i = 0; i < keyword_help_len; i++) { if (package == NULL || strcasecmp(package, keyword_help[i].package) != 0) { package = keyword_help[i].package; + _buf.append(TWISTY1_OPEN, TWISTY1_LEN); _buf.append(package); _buf.append("\n", 1); } @@ -1588,23 +1602,6 @@ void TextEditHelpWidget::createKeywordIndex() { } } -void TextEditHelpWidget::createPackageIndex() { - char *package = lineText(_state.cursor); - if (package[0] != '\0' && package[0] != '[') { - reset(kKeywordPackageIndex); - _buf.append("[", 1); - _buf.append(package); - _buf.append("]\n", 2); - for (int i = 0; i < keyword_help_len; i++) { - if (strcasecmp(package, keyword_help[i].package) == 0) { - _buf.append(keyword_help[i].keyword); - _buf.append("\n", 1); - } - } - } - free(package); -} - bool TextEditHelpWidget::createKeywordHelp(const char *keyword) { bool found = false; for (int i = 0; i < keyword_help_len; i++) { @@ -1712,3 +1709,68 @@ void TextEditHelpWidget::reset(HelpMode mode) { _scroll = 0; _matchingBrace = -1; } + +bool TextEditHelpWidget::selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw) { + bool result = hasFocus(); + if (result) { + dragPage(pt.y, redraw); + } + return result; +} + +void TextEditHelpWidget::toggleKeyword() { + char *line = lineText(_state.cursor); + bool open1 = strncmp(line, TWISTY1_OPEN, TWISTY1_LEN) == 0; + bool open2 = strncmp(line, TWISTY2_OPEN, TWISTY2_LEN) == 0; + bool close1 = strncmp(line, TWISTY1_CLOSE, TWISTY1_LEN) == 0; + bool close2 = strncmp(line, TWISTY2_CLOSE, TWISTY2_LEN) == 0; + if (open1 || open2 || close1 || close2) { + const char *nextLine = line + TWISTY1_LEN; + const char *package = (open2 || close2) && _openPackage != NULL ? _openPackage : nextLine; + const char *nextPackage = NULL; + _buf.clear(); + _matchingBrace = -1; + for (int i = 0; i < keyword_help_len; i++) { + if (nextPackage == NULL || strcasecmp(nextPackage, keyword_help[i].package) != 0) { + nextPackage = keyword_help[i].package; + if (strcasecmp(package, nextPackage) == 0) { + // selected item + _buf.append(open1 || open2 || close2 ? TWISTY1_CLOSE : TWISTY1_OPEN, TWISTY1_LEN); + _buf.append(nextPackage); + _buf.append("\n", 1); + if (open1) { + _openPackage = nextPackage; + } else if (open2) { + nextLine = line + TWISTY2_LEN; + } + if (open1 || open2 || close2) { + while (i < keyword_help_len && + strcasecmp(nextPackage, keyword_help[i].package) == 0) { + if (open2 && strcasecmp(nextLine, keyword_help[i].keyword) == 0) { + _buf.append(TWISTY2_CLOSE, TWISTY2_LEN); + _buf.append(keyword_help[i].keyword); + _buf.append("\n\n", 2); + _buf.append(keyword_help[i].signature); + _buf.append("\n\n", 2); + _buf.append(keyword_help[i].help); + _buf.append("\n\n", 2); + } else { + _buf.append(TWISTY2_OPEN, TWISTY2_LEN); + _buf.append(keyword_help[i].keyword); + _buf.append("\n", 1); + } + i++; + } + } + } else { + // next item + _buf.append(TWISTY1_OPEN, TWISTY1_LEN); + _buf.append(nextPackage); + _buf.append("\n", 1); + } + } + } + } + free(line); +} + diff --git a/src/ui/textedit.h b/src/ui/textedit.h index f0af64ff..f0953c3e 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -116,6 +116,7 @@ struct TextEditInput : public FormEditInput { kDigit, }; + void dragPage(int y, bool &redraw); void drawText(int x, int y, const char *str, int length, SyntaxState &state); void changeCase(); void cycleTheme(); @@ -170,7 +171,6 @@ struct TextEditHelpWidget : public TextEditInput { kCompletion, kKeyword, kKeywordIndex, - kKeywordPackageIndex, kOutline, kSearch, kSearchReplace, @@ -180,6 +180,7 @@ struct TextEditHelpWidget : public TextEditInput { kMessage }; + void clicked(int x, int y, bool pressed); void createCompletionHelp(); void createGotoLine(); void createHelp(); @@ -196,6 +197,8 @@ struct TextEditHelpWidget : public TextEditInput { bool closeOnEnter() const; bool replaceMode() const { return _mode == kReplace; } bool replaceDoneMode() const { return _mode == kReplaceDone; } + bool selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw); + void toggleKeyword(); private: void completeLine(int pos); @@ -206,6 +209,7 @@ struct TextEditHelpWidget : public TextEditInput { HelpMode _mode; strlib::List _outline; TextEditInput *_editor; + const char *_openPackage; }; #define STB_TEXTEDIT_STRING EditBuffer From 2deb2edd9d56139223b3b6a559458e5c0190b554 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 29 Sep 2015 07:20:20 +1000 Subject: [PATCH 10/30] UI: update help --- src/ui/textedit.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 798c4ef3..5d2e50f5 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -25,10 +25,10 @@ #define INDENT_LEVEL 2 #define HELP_WIDTH 22 #define NUM_THEMES 4 -#define TWISTY1_OPEN "| " -#define TWISTY1_CLOSE "|_" -#define TWISTY2_OPEN " | " -#define TWISTY2_CLOSE " |_" +#define TWISTY1_OPEN "> " +#define TWISTY1_CLOSE "< " +#define TWISTY2_OPEN " > " +#define TWISTY2_CLOSE " < " #define TWISTY1_LEN 2 #define TWISTY2_LEN 4 From e99806a4e233220dfa14456b3d3376e5a6a2a2e7 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 1 Oct 2015 07:00:16 +1000 Subject: [PATCH 11/30] UI: update help --- ChangeLog | 4 ++++ configure.ac | 2 +- debian/changelog | 2 +- ide/android/assets/main.bas | 2 +- src/platform/sdl/editor.cpp | 3 +++ src/platform/sdl/runtime.cpp | 10 +++++++++- src/ui/screen.h | 4 ++-- src/ui/textedit.cpp | 21 ++++++++++----------- src/ui/textedit.h | 2 +- 9 files changed, 32 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2c82f20f..25bdbd60 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,10 @@ 2015-09-15 SDL Update PEN(3) to work more like FLTK Fix display output before PEN + Fix BOLD and ITALIC font display + Context menu edit keyword completion + Updated program icon + Editor line number widget can be used for scrolling 2015-08-26 Editor fixes: diff --git a/configure.ac b/configure.ac index 22a7d56c..90f10299 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ dnl This program is distributed under the terms of the GPL v2.0 dnl Download the GNU Public License (GPL) from www.gnu.org dnl -AC_INIT([smallbasic], [0.11.21]) +AC_INIT([smallbasic], [0.12.0]) AC_CONFIG_SRCDIR([configure.ac]) AC_CANONICAL_TARGET diff --git a/debian/changelog b/debian/changelog index cb68d7cc..b786966a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -smallbasic (0.11.21) unstable; urgency=low +smallbasic (0.12.0) unstable; urgency=low * Various - see web site -- Chris Warren-Smith Sat, 17 Sept 2015 09:45:25 +1000 diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index bcd71c44..066e0731 100644 --- a/ide/android/assets/main.bas +++ b/ide/android/assets/main.bas @@ -55,7 +55,7 @@ sub do_about() print "(_ ._ _ _.|||_) /\ (_ |/ " print "__)| | |(_||||_)/--\__)|\_" print - print "Version 0.11.21" + print "Version 0.12.0" print print "Copyright (c) 2002-2015 Chris Warren-Smith" print "Copyright (c) 1999-2006 Nic Christopoulos" + chr(10) diff --git a/src/platform/sdl/editor.cpp b/src/platform/sdl/editor.cpp index 09c279fb..a17f8f95 100644 --- a/src/platform/sdl/editor.cpp +++ b/src/platform/sdl/editor.cpp @@ -221,6 +221,9 @@ void System::editSource(strlib::String &loadPath) { _output->redraw(); } } else if (event.type == EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED) { + if (editWidget->isDirty()) { + _output->setStatus(dirtyFile); + } _output->redraw(); } diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 237ce423..d6d91955 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -706,7 +706,15 @@ bool System::getPen3() { void System::completeKeyword(int index) { if (get_focus_edit() && isEditing()) { - get_focus_edit()->completeKeyword(index); + TextEditInput *editWidget = (TextEditInput *)get_focus_edit(); + char *preWord = editWidget->getWordBeforeCursor(); + const char *help = get_focus_edit()->completeKeyword(index); + char *word = editWidget->getWordBeforeCursor(); + if (help && (preWord != NULL && strlen(preWord) == strlen(word))) { + runtime->alert("", help); + } + free(preWord); + free(word); } } diff --git a/src/ui/screen.h b/src/ui/screen.h index e9e6857e..bbcfbcc2 100755 --- a/src/ui/screen.h +++ b/src/ui/screen.h @@ -107,7 +107,7 @@ struct GraphicScreen : public Screen { void reset(int fontSize); bool setGraphicsRendition(const char c, int escValue, int lineHeight); void setPixel(int x, int y, int c); - void resize(int newWidth, int newHeight, int oldWidth, + void resize(int newWidth, int newHeight, int oldWidth, int oldHeight, int lineHeight); void updateFont() { setFont(_bold, _italic, _fontSize); } int getPixel(int x, int y); @@ -322,7 +322,7 @@ struct TextScreen : public Screen { void inset(int x, int y, int w, int h, Screen *over); void newLine(int lineHeight); int print(const char *p, int lineHeight, bool allChars=false); - void resize(int newWidth, int newHeight, int oldWidth, + void resize(int newWidth, int newHeight, int oldWidth, int oldHeight, int lineHeight); bool setGraphicsRendition(const char c, int escValue, int lineHeight); void setOver(Screen *over) { _over = over; } diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 5d2e50f5..24f52d0c 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -307,7 +307,7 @@ const char *TextEditInput::completeKeyword(int index) { for (int i = 0; i < keyword_help_len; i++) { if (strncasecmp(selection, keyword_help[i].keyword, len) == 0 && count++ == index) { - if (IS_WHITE(_buf._buffer[_state.cursor])) { + if (IS_WHITE(_buf._buffer[_state.cursor]) || _buf._buffer[_state.cursor] == '\0') { completeWord(keyword_help[i].keyword); } help = keyword_help[i].help; @@ -1050,7 +1050,7 @@ void TextEditInput::findMatchingBrace() { int TextEditInput::getCompletions(StringList *list, int max) { int count = 0; char *selection = getWordBeforeCursor(); - int len = selection != NULL ? strlen(selection) : 0; + unsigned len = selection != NULL ? strlen(selection) : 0; if (len > 0) { for (int i = 0; i < keyword_help_len && count < max; i++) { if (strncasecmp(selection, keyword_help[i].keyword, len) == 0) { @@ -1422,7 +1422,8 @@ TextEditHelpWidget::TextEditHelpWidget(TextEditInput *editor, int chW, int chH) chW * HELP_WIDTH, editor->_height), _mode(kNone), _editor(editor), - _openPackage(NULL) { + _openPackage(NULL), + _openKeyword(-1) { _theme = new EditTheme(0x73c990, 0x20242a); hide(); } @@ -1432,9 +1433,7 @@ TextEditHelpWidget::~TextEditHelpWidget() { } bool TextEditHelpWidget::closeOnEnter() const { - return (_mode != kSearch && - _mode != kKeyword && - _mode != kKeywordIndex); + return (_mode != kSearch && _mode != kKeyword && _mode != kKeywordIndex); } bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { @@ -1497,16 +1496,15 @@ bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { case kKeywordIndex: toggleKeyword(); break; - case kKeyword: - _mode = kHelp; - completeLine(0); - break; default: break; } result = true; break; default: + if (_mode == kKeywordIndex && _openKeyword != -1 && key < 0) { + result = TextEditInput::edit(key, screenWidth, charWidth); + } break; } } @@ -1730,6 +1728,7 @@ void TextEditHelpWidget::toggleKeyword() { const char *nextPackage = NULL; _buf.clear(); _matchingBrace = -1; + _openKeyword = -1; for (int i = 0; i < keyword_help_len; i++) { if (nextPackage == NULL || strcasecmp(nextPackage, keyword_help[i].package) != 0) { nextPackage = keyword_help[i].package; @@ -1747,6 +1746,7 @@ void TextEditHelpWidget::toggleKeyword() { while (i < keyword_help_len && strcasecmp(nextPackage, keyword_help[i].package) == 0) { if (open2 && strcasecmp(nextLine, keyword_help[i].keyword) == 0) { + _openKeyword = i; _buf.append(TWISTY2_CLOSE, TWISTY2_LEN); _buf.append(keyword_help[i].keyword); _buf.append("\n\n", 2); @@ -1773,4 +1773,3 @@ void TextEditHelpWidget::toggleKeyword() { } free(line); } - diff --git a/src/ui/textedit.h b/src/ui/textedit.h index f0953c3e..7fea35e7 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -189,7 +189,6 @@ struct TextEditHelpWidget : public TextEditInput { void createOutline(); void createSearch(bool replace); bool edit(int key, int screenWidth, int charWidth); - char *copy(bool cut) { return NULL; } void paste(const char *text) {} bool isDrawTop() { return true; } void resize(int w, int h) { _x = w - _width; _height = h; } @@ -210,6 +209,7 @@ struct TextEditHelpWidget : public TextEditInput { strlib::List _outline; TextEditInput *_editor; const char *_openPackage; + int _openKeyword; }; #define STB_TEXTEDIT_STRING EditBuffer From d0e187cc38eaa21a9cc21704c908f1f1d87680a6 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 2 Oct 2015 06:32:15 +1000 Subject: [PATCH 12/30] UI: update help --- ChangeLog | 1 + src/platform/sdl/editor.cpp | 3 --- src/platform/sdl/runtime.cpp | 9 ++----- src/ui/textedit.cpp | 51 +++++++++++++++++------------------- src/ui/textedit.h | 4 +-- 5 files changed, 28 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index 25bdbd60..9a5fa6de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ Context menu edit keyword completion Updated program icon Editor line number widget can be used for scrolling + Updated editor help display 2015-08-26 Editor fixes: diff --git a/src/platform/sdl/editor.cpp b/src/platform/sdl/editor.cpp index a17f8f95..09c279fb 100644 --- a/src/platform/sdl/editor.cpp +++ b/src/platform/sdl/editor.cpp @@ -221,9 +221,6 @@ void System::editSource(strlib::String &loadPath) { _output->redraw(); } } else if (event.type == EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED) { - if (editWidget->isDirty()) { - _output->setStatus(dirtyFile); - } _output->redraw(); } diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index d6d91955..3c98d33b 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -706,15 +706,10 @@ bool System::getPen3() { void System::completeKeyword(int index) { if (get_focus_edit() && isEditing()) { - TextEditInput *editWidget = (TextEditInput *)get_focus_edit(); - char *preWord = editWidget->getWordBeforeCursor(); const char *help = get_focus_edit()->completeKeyword(index); - char *word = editWidget->getWordBeforeCursor(); - if (help && (preWord != NULL && strlen(preWord) == strlen(word))) { - runtime->alert("", help); + if (help) { + runtime->getOutput()->setStatus(help); } - free(preWord); - free(word); } } diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 24f52d0c..252a64f5 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -1433,7 +1433,7 @@ TextEditHelpWidget::~TextEditHelpWidget() { } bool TextEditHelpWidget::closeOnEnter() const { - return (_mode != kSearch && _mode != kKeyword && _mode != kKeywordIndex); + return (_mode != kSearch && _mode != kHelpKeyword); } bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { @@ -1493,7 +1493,7 @@ bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { case kCompletion: completeWord(_state.cursor); break; - case kKeywordIndex: + case kHelpKeyword: toggleKeyword(); break; default: @@ -1502,7 +1502,7 @@ bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { result = true; break; default: - if (_mode == kKeywordIndex && _openKeyword != -1 && key < 0) { + if (_mode == kHelpKeyword && _openKeyword != -1 && key < 0) { result = TextEditInput::edit(key, screenWidth, charWidth); } break; @@ -1535,7 +1535,7 @@ void TextEditHelpWidget::clicked(int x, int y, bool pressed) { _ptY = -1; if (pressed) { stb_textedit_click(&_buf, &_state, 0, y + (_scroll * _charHeight)); - if (_mode == kKeywordIndex && x - _x <= _charWidth * 3) { + if (_mode == kHelpKeyword && x - _x <= _charWidth * 3) { toggleKeyword(); } } @@ -1580,14 +1580,25 @@ void TextEditHelpWidget::createHelp() { } void TextEditHelpWidget::createKeywordIndex() { - char *selection = _editor->getWordBeforeCursor(); - bool foundKeyword = false; - if (selection != NULL) { - foundKeyword = createKeywordHelp(selection); - free(selection); + char *keyword = _editor->getWordBeforeCursor(); + reset(kHelpKeyword); + + bool keywordFound = false; + if (keyword != NULL) { + for (int i = 0; i < keyword_help_len && !keywordFound; i++) { + if (strcasecmp(keyword, keyword_help[i].keyword) == 0) { + _buf.append(TWISTY2_OPEN, TWISTY2_LEN); + _buf.append(keyword_help[i].keyword); + _openPackage = keyword_help[i].package; + keywordFound = true; + toggleKeyword(); + break; + } + } + free(keyword); } - if (!foundKeyword) { - reset(kKeywordIndex); + + if (!keywordFound) { const char *package = NULL; for (int i = 0; i < keyword_help_len; i++) { if (package == NULL || strcasecmp(package, keyword_help[i].package) != 0) { @@ -1600,22 +1611,6 @@ void TextEditHelpWidget::createKeywordIndex() { } } -bool TextEditHelpWidget::createKeywordHelp(const char *keyword) { - bool found = false; - for (int i = 0; i < keyword_help_len; i++) { - if (strcasecmp(keyword, keyword_help[i].keyword) == 0) { - reset(kKeyword); - _buf.append(keyword_help[i].signature); - _buf.append("\n\n", 2); - _buf.append(keyword_help[i].help); - _buf.append("\n", 1); - found = true; - break; - } - } - return found; -} - void TextEditHelpWidget::createOutline() { const char *text = _editor->getText(); int len = _editor->getTextLength(); @@ -1729,6 +1724,7 @@ void TextEditHelpWidget::toggleKeyword() { _buf.clear(); _matchingBrace = -1; _openKeyword = -1; + _state.select_start = _state.select_end = 0; for (int i = 0; i < keyword_help_len; i++) { if (nextPackage == NULL || strcasecmp(nextPackage, keyword_help[i].package) != 0) { nextPackage = keyword_help[i].package; @@ -1750,6 +1746,7 @@ void TextEditHelpWidget::toggleKeyword() { _buf.append(TWISTY2_CLOSE, TWISTY2_LEN); _buf.append(keyword_help[i].keyword); _buf.append("\n\n", 2); + _state.cursor = _buf._len; _buf.append(keyword_help[i].signature); _buf.append("\n\n", 2); _buf.append(keyword_help[i].help); diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 7fea35e7..99ce2119 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -168,9 +168,8 @@ struct TextEditHelpWidget : public TextEditInput { enum HelpMode { kNone, kHelp, + kHelpKeyword, kCompletion, - kKeyword, - kKeywordIndex, kOutline, kSearch, kSearchReplace, @@ -203,7 +202,6 @@ struct TextEditHelpWidget : public TextEditInput { void completeLine(int pos); void completeWord(int pos); void createPackageIndex(); - bool createKeywordHelp(const char *keyword); HelpMode _mode; strlib::List _outline; From 658b389399606d0a4bb08b30b26ab84936c087ca Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 3 Oct 2015 06:36:15 +1000 Subject: [PATCH 13/30] ANDROID: update edit help --- ide/android/assets/main.bas | 3 ++ src/platform/android/jni/runtime.cpp | 49 +++++++++++++++++++--------- src/ui/system.cpp | 21 +++++++++--- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index 066e0731..1a997e24 100644 --- a/ide/android/assets/main.bas +++ b/ide/android/assets/main.bas @@ -90,6 +90,9 @@ sub do_newfile() local valid_file = false while (!valid_file) input "Enter file name: ", file + if (len(file) == 0) then + exit loop + endif if (leftoflast(file, ".bas") == 0) then file += ".bas" endif diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 8f47c528..06cedf6c 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -1,6 +1,6 @@ // This file is part of SmallBASIC // -// Copyright(C) 2001-2014 Chris Warren-Smith. +// Copyright(C) 2001-2015 Chris Warren-Smith. // // This program is distributed under the terms of the GPL v2.0 or later // Download the GNU Public License (GPL) from www.gnu.org @@ -34,8 +34,6 @@ Runtime *runtime; -void launchDebug(const char *file) {} - MAEvent *getMotionEvent(int type, AInputEvent *event) { MAEvent *result = new MAEvent(); result->type = type; @@ -767,47 +765,57 @@ void System::editSource(strlib::String &loadPath) { int charWidth = _output->getCharWidth(); int charHeight = _output->getCharHeight(); int prevScreenId = _output->selectScreen(SOURCE_SCREEN); - TextEditInput *widget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); + TextEditInput *editWidget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); + TextEditHelpWidget *helpWidget = new TextEditHelpWidget(editWidget, charWidth, charHeight); + TextEditInput *widget = editWidget; _modifiedTime = getModifiedTime(); - widget->updateUI(NULL, NULL); - widget->setLineNumbers(); - widget->setFocus(true); + editWidget->updateUI(NULL, NULL); + editWidget->setLineNumbers(); + editWidget->setFocus(true); if (strcmp(gsb_last_file, loadPath.c_str()) == 0) { - widget->setCursorRow(gsb_last_line - 1); + editWidget->setCursorRow(gsb_last_line - 1); } if (gsb_last_error && !isBack()) { - widget->setCursorRow(gsb_last_line - 1); + editWidget->setCursorRow(gsb_last_line - 1); runtime->alert(gsb_last_errmsg); } _srcRendered = false; _output->clearScreen(); - _output->addInput(widget); + _output->addInput(editWidget); + _output->addInput(helpWidget); _output->setStatus(cleanFile); _output->redraw(); _state = kEditState; + runtime->showKeypad(true); - maShowVirtualKeyboard(); while (_state == kEditState) { MAEvent event = getNextEvent(); if (event.type == EVENT_TYPE_KEY_PRESSED && _userScreenId == -1) { dev_clrkb(); int sw = _output->getScreenWidth(); bool redraw = true; - bool dirty = widget->isDirty(); + bool dirty = editWidget->isDirty(); char *text; switch (event.key) { case SB_KEY_MENU: redraw = false; break; + case SB_KEY_F(1): + widget = helpWidget; + helpWidget->createKeywordIndex(); + helpWidget->show(); + helpWidget->setFocus(true); + runtime->showKeypad(false); + break; case SB_KEY_F(9): _state = kRunState; - if (widget->isDirty()) { - saveFile(widget, loadPath); + if (editWidget->isDirty()) { + saveFile(editWidget, loadPath); } break; case SB_KEY_CTRL('s'): - saveFile(widget, loadPath); + saveFile(editWidget, loadPath); break; case SB_KEY_CTRL('c'): case SB_KEY_CTRL('x'): @@ -828,7 +836,7 @@ void System::editSource(strlib::String &loadPath) { _output->redraw(); _state = kActiveState; waitForBack(); - maShowVirtualKeyboard(); + runtime->showKeypad(true); _output->selectScreen(SOURCE_SCREEN); _state = kEditState; break; @@ -848,6 +856,15 @@ void System::editSource(strlib::String &loadPath) { _output->redraw(); } + if (isBack() && widget == helpWidget) { + runtime->showKeypad(true); + widget = editWidget; + helpWidget->hide(); + editWidget->setFocus(true); + _state = kEditState; + _output->redraw(); + } + if (widget->isDirty()) { int choice = -1; if (isClosing()) { diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 3500f148..be54afe1 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -40,7 +40,8 @@ #define MENU_RUN 17 #define MENU_DEBUG 18 #define MENU_OUTPUT 19 -#define MENU_SIZE 20 +#define MENU_HELP 20 +#define MENU_SIZE 21 #define MENU_COMPETION_0 (MENU_SIZE + 1) #define MENU_COMPETION_1 (MENU_SIZE + 2) #define MENU_COMPETION_2 (MENU_SIZE + 3) @@ -285,8 +286,12 @@ void System::handleMenu(MAEvent &event) { } break; case MENU_EDITMODE: +#if defined(_SDL) opt_ide = (opt_ide == IDE_NONE ? IDE_INTERNAL : opt_ide == IDE_INTERNAL ? IDE_EXTERNAL : IDE_NONE); +#else + opt_ide = (opt_ide == IDE_NONE ? IDE_INTERNAL : IDE_NONE); +#endif break; case MENU_AUDIO: opt_mute_audio = !opt_mute_audio; @@ -318,6 +323,10 @@ void System::handleMenu(MAEvent &event) { event.type = EVENT_TYPE_KEY_PRESSED; event.key = SB_KEY_CTRL('o'); break; + case MENU_HELP: + event.type = EVENT_TYPE_KEY_PRESSED; + event.key = SB_KEY_F(1); + break; case MENU_COMPETION_0: completeKeyword(0); break; @@ -542,7 +551,7 @@ void System::runMain(const char *mainBasPath) { if (!isClosing() && _overruns) { systemPrint("\nOverruns: %d\n", _overruns); } - if (!isBack() && !isClosing() && opt_ide != IDE_INTERNAL) { + if (!isBack() && !isClosing() && (opt_ide != IDE_INTERNAL || success)) { // load the next network file without displaying the previous result bool networkFile = (_loadPath.indexOf("://", 1) != -1); if (!_mainBas && !networkFile) { @@ -748,8 +757,9 @@ void System::showMenu() { items->add(new String("Run")); #if defined(_SDL) items->add(new String("Debug")); -#endif items->add(new String("Show output")); +#endif + items->add(new String("Help")); for (int i = 0; i < completions; i++) { _systemMenu[index++] = MENU_COMPETION_0 + i; } @@ -762,8 +772,9 @@ void System::showMenu() { _systemMenu[index++] = MENU_RUN; #if defined(_SDL) _systemMenu[index++] = MENU_DEBUG; -#endif _systemMenu[index++] = MENU_OUTPUT; +#endif + _systemMenu[index++] = MENU_HELP; } else if (isRunning()) { items->add(new String("Cut")); items->add(new String("Copy")); @@ -810,7 +821,7 @@ void System::showMenu() { _systemMenu[index++] = MENU_ZOOM_UP; _systemMenu[index++] = MENU_ZOOM_DN; sprintf(buffer, "Editor [%s]", (opt_ide == IDE_NONE ? "OFF" : - opt_ide == IDE_EXTERNAL ? "Live Mode" : "ON")); + opt_ide == IDE_INTERNAL ? "ON" : "Live Mode")); items->add(new String(buffer)); _systemMenu[index++] = MENU_EDITMODE; } From 7c817dc6d0e7727ca2a5d6f18f081c6960a68ef5 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 3 Oct 2015 18:09:44 +1000 Subject: [PATCH 14/30] UI: fix help scrolling --- src/platform/sdl/editor.cpp | 2 -- src/ui/textedit.cpp | 24 ++++++++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/platform/sdl/editor.cpp b/src/platform/sdl/editor.cpp index 09c279fb..032be6dd 100644 --- a/src/platform/sdl/editor.cpp +++ b/src/platform/sdl/editor.cpp @@ -220,8 +220,6 @@ void System::editSource(strlib::String &loadPath) { if (redraw) { _output->redraw(); } - } else if (event.type == EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED) { - _output->redraw(); } if ((isBack() || isClosing()) && editWidget->isDirty()) { diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 252a64f5..f142051f 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -1721,32 +1721,46 @@ void TextEditHelpWidget::toggleKeyword() { const char *nextLine = line + TWISTY1_LEN; const char *package = (open2 || close2) && _openPackage != NULL ? _openPackage : nextLine; const char *nextPackage = NULL; + int pageRows = _height / _charHeight; + int open1Count = 0; + int open2Count = 0; _buf.clear(); _matchingBrace = -1; _openKeyword = -1; _state.select_start = _state.select_end = 0; + for (int i = 0; i < keyword_help_len; i++) { if (nextPackage == NULL || strcasecmp(nextPackage, keyword_help[i].package) != 0) { nextPackage = keyword_help[i].package; if (strcasecmp(package, nextPackage) == 0) { // selected item + if (open1 || close1) { + _state.cursor = _buf._len; + _cursorRow = open1Count; + } + _buf.append(open1 || open2 || close2 ? TWISTY1_CLOSE : TWISTY1_OPEN, TWISTY1_LEN); _buf.append(nextPackage); _buf.append("\n", 1); + if (open1) { _openPackage = nextPackage; + open1Count++; } else if (open2) { nextLine = line + TWISTY2_LEN; + open2Count++; } if (open1 || open2 || close2) { while (i < keyword_help_len && strcasecmp(nextPackage, keyword_help[i].package) == 0) { + open2Count++; if (open2 && strcasecmp(nextLine, keyword_help[i].keyword) == 0) { _openKeyword = i; + _state.cursor = _buf._len; + _cursorRow = open1Count + open2Count; _buf.append(TWISTY2_CLOSE, TWISTY2_LEN); _buf.append(keyword_help[i].keyword); _buf.append("\n\n", 2); - _state.cursor = _buf._len; _buf.append(keyword_help[i].signature); _buf.append("\n\n", 2); _buf.append(keyword_help[i].help); @@ -1760,13 +1774,19 @@ void TextEditHelpWidget::toggleKeyword() { } } } else { - // next item + // next package item (level 1) _buf.append(TWISTY1_OPEN, TWISTY1_LEN); _buf.append(nextPackage); _buf.append("\n", 1); + open1Count++; } } } + if (_cursorRow + 4 < pageRows) { + _scroll = 0; + } else { + _scroll = _cursorRow - (pageRows / 4); + } } free(line); } From b5c30e23385fd68b3470196266f84042154de936 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 5 Oct 2015 09:17:33 +1000 Subject: [PATCH 15/30] UI: update help --- src/platform/android/jni/runtime.cpp | 4 +--- src/ui/textedit.cpp | 11 +++++++---- src/ui/textedit.h | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 06cedf6c..bcc88104 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -766,7 +766,7 @@ void System::editSource(strlib::String &loadPath) { int charHeight = _output->getCharHeight(); int prevScreenId = _output->selectScreen(SOURCE_SCREEN); TextEditInput *editWidget = new TextEditInput(_programSrc, charWidth, charHeight, 0, 0, w, h); - TextEditHelpWidget *helpWidget = new TextEditHelpWidget(editWidget, charWidth, charHeight); + TextEditHelpWidget *helpWidget = new TextEditHelpWidget(editWidget, charWidth, charHeight, false); TextEditInput *widget = editWidget; _modifiedTime = getModifiedTime(); editWidget->updateUI(NULL, NULL); @@ -852,8 +852,6 @@ void System::editSource(strlib::String &loadPath) { if (redraw) { _output->redraw(); } - } else if (event.type == EVENT_TYPE_OPTIONS_BOX_BUTTON_CLICKED) { - _output->redraw(); } if (isBack() && widget == helpWidget) { diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index f142051f..8f5d424b 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -310,7 +310,7 @@ const char *TextEditInput::completeKeyword(int index) { if (IS_WHITE(_buf._buffer[_state.cursor]) || _buf._buffer[_state.cursor] == '\0') { completeWord(keyword_help[i].keyword); } - help = keyword_help[i].help; + help = keyword_help[i].signature; break; } } @@ -1417,15 +1417,18 @@ int TextEditInput::wordStart() { // // TextEditHelpWidget // -TextEditHelpWidget::TextEditHelpWidget(TextEditInput *editor, int chW, int chH) : - TextEditInput(NULL, chW, chH, editor->_width - (chW * HELP_WIDTH), editor->_y, - chW * HELP_WIDTH, editor->_height), +TextEditHelpWidget::TextEditHelpWidget(TextEditInput *editor, int chW, int chH, bool overlay) : + TextEditInput(NULL, chW, chH, editor->_x, editor->_y, editor->_width, editor->_height), _mode(kNone), _editor(editor), _openPackage(NULL), _openKeyword(-1) { _theme = new EditTheme(0x73c990, 0x20242a); hide(); + if (overlay) { + _x = editor->_width - (chW * HELP_WIDTH); + _width = chW * HELP_WIDTH; + } } TextEditHelpWidget::~TextEditHelpWidget() { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 99ce2119..c4e57f07 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -162,7 +162,7 @@ struct TextEditInput : public FormEditInput { }; struct TextEditHelpWidget : public TextEditInput { - TextEditHelpWidget(TextEditInput *editor, int chW, int chH); + TextEditHelpWidget(TextEditInput *editor, int chW, int chH, bool overlay=true); virtual ~TextEditHelpWidget(); enum HelpMode { From f64e0c1127302506a25f3783520f183d02dd9e95 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 6 Oct 2015 22:24:39 +1000 Subject: [PATCH 16/30] UI: fix line wrapped comments --- src/ui/textedit.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 8f5d424b..5af1e013 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -347,6 +347,7 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { if (i == 0 || _buf._buffer[i - 1] == '\r' || _buf._buffer[i - 1] == '\n') { + syntax = kReset; line++; } @@ -433,6 +434,19 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { } } baseY += _charHeight; + } else if (row <= _scroll && syntax == kReset) { + int end = i + r.num_chars - 1; + if (_buf._buffer[end] != '\r' && + _buf._buffer[end] != '\n') { + // line continues + for (int j = i; j < end; j++) { + // line also 'ends' at start of comments + if (is_comment(_buf._buffer, j)) { + syntax = kComment; + break; + } + } + } } i += r.num_chars; } From 67967f0f3fb28d7064e361da21aee18e086915b0 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 7 Oct 2015 07:10:05 +1000 Subject: [PATCH 17/30] UI: fix line wrapped comments --- src/ui/textedit.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 5af1e013..8bf94a89 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -438,12 +438,14 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { int end = i + r.num_chars - 1; if (_buf._buffer[end] != '\r' && _buf._buffer[end] != '\n') { - // line continues + // scrolled line continues to next line for (int j = i; j < end; j++) { - // line also 'ends' at start of comments if (is_comment(_buf._buffer, j)) { syntax = kComment; break; + } else if (_buf._buffer[j] == '\"') { + syntax = kText; + break; } } } From f556382c23c0b0295d96afefe4558c17967e2608 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 8 Oct 2015 21:04:06 +1000 Subject: [PATCH 18/30] UI: fix line wrapped comments --- src/platform/sdl/runtime.cpp | 1 + src/ui/system.cpp | 2 +- src/ui/textedit.cpp | 39 ++++++++++++++++++++++-------------- src/ui/textedit.h | 3 +-- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/platform/sdl/runtime.cpp b/src/platform/sdl/runtime.cpp index 3c98d33b..68c62df2 100644 --- a/src/platform/sdl/runtime.cpp +++ b/src/platform/sdl/runtime.cpp @@ -709,6 +709,7 @@ void System::completeKeyword(int index) { const char *help = get_focus_edit()->completeKeyword(index); if (help) { runtime->getOutput()->setStatus(help); + runtime->getOutput()->redraw(); } } } diff --git a/src/ui/system.cpp b/src/ui/system.cpp index be54afe1..2de80661 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -757,7 +757,7 @@ void System::showMenu() { items->add(new String("Run")); #if defined(_SDL) items->add(new String("Debug")); - items->add(new String("Show output")); + items->add(new String("Show Output")); #endif items->add(new String("Help")); for (int i = 0; i < completions; i++) { diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 8bf94a89..f04a514a 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -33,6 +33,9 @@ #define TWISTY2_LEN 4 int g_themeId = 0; +int g_lineMarker[MAX_MARKERS] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; const int theme1[] = { 0xc8cedb, 0xa7aebc, 0x484f5f, 0xa7aebc, 0xa7aebc, 0x00bb00, @@ -113,6 +116,10 @@ int compareIntegers(const void *p1, const void *p2) { return i1 < i2 ? -1 : i1 == i2 ? 0 : 1; } +void init_edit_markers() { + +} + // // EditTheme // @@ -273,7 +280,6 @@ TextEditInput::TextEditInput(const char *text, int chW, int chH, _ptY(-1), _dirty(false) { stb_textedit_initialize_state(&_state, false); - memset(_lineMarker, -1, sizeof(_lineMarker)); } TextEditInput::~TextEditInput() { @@ -444,8 +450,7 @@ void TextEditInput::draw(int x, int y, int w, int h, int chw) { syntax = kComment; break; } else if (_buf._buffer[j] == '\"') { - syntax = kText; - break; + syntax = (syntax == kText) ? kReset : kText; } } } @@ -677,6 +682,10 @@ bool TextEditInput::find(const char *word, bool next) { return result; } +int *TextEditInput::getMarkers() { + return g_lineMarker; +} + void TextEditInput::gotoLine(const char *buffer) { if (_buf._buffer != NULL && buffer != NULL) { setCursorRow(atoi(buffer) - 1); @@ -886,7 +895,7 @@ void TextEditInput::drawLineNumber(int x, int y, int row, bool selected) { if (_marginWidth > 0) { bool markerRow = false; for (int i = 0; i < MAX_MARKERS && !markerRow; i++) { - if (row == _lineMarker[i]) { + if (row == g_lineMarker[i]) { markerRow = true; } } @@ -1230,22 +1239,22 @@ void TextEditInput::gotoNextMarker() { int next = 0; int first = -1; for (int i = 0; i < MAX_MARKERS; i++) { - if (_lineMarker[i] != -1) { + if (g_lineMarker[i] != -1) { if (first == -1) { first = i; } - if (_lineMarker[i] == _cursorLine) { + if (g_lineMarker[i] == _cursorLine) { next = i + 1 == MAX_MARKERS ? first : i + 1; break; } } } if (first != -1) { - if (_lineMarker[next] == -1) { + if (g_lineMarker[next] == -1) { next = first; } - if (_lineMarker[next] != -1) { - setCursorRow(_lineMarker[next] - 1); + if (g_lineMarker[next] != -1) { + setCursorRow(g_lineMarker[next] - 1); } } } @@ -1393,24 +1402,24 @@ void TextEditInput::setColor(SyntaxState &state) { void TextEditInput::toggleMarker() { bool found = false; for (int i = 0; i < MAX_MARKERS && !found; i++) { - if (_cursorLine == _lineMarker[i]) { - _lineMarker[i] = -1; + if (_cursorLine == g_lineMarker[i]) { + g_lineMarker[i] = -1; found = true; } } if (!found) { for (int i = 0; i < MAX_MARKERS && !found; i++) { - if (_lineMarker[i] == -1) { - _lineMarker[i] = _cursorLine; + if (g_lineMarker[i] == -1) { + g_lineMarker[i] = _cursorLine; found = true; break; } } } if (!found) { - _lineMarker[0] = _cursorLine; + g_lineMarker[0] = _cursorLine; } - qsort(_lineMarker, MAX_MARKERS, sizeof(int), compareIntegers); + qsort(g_lineMarker, MAX_MARKERS, sizeof(int), compareIntegers); } void TextEditInput::updateScroll() { diff --git a/src/ui/textedit.h b/src/ui/textedit.h index c4e57f07..e77f8162 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -80,7 +80,7 @@ struct TextEditInput : public FormEditInput { int getCursorPos() const { return _state.cursor; } const char *getText() const { return _buf._buffer; } int getTextLength() const { return _buf._len; } - int *getMarkers() { return _lineMarker; } + int *getMarkers(); void gotoLine(const char *buffer); void reload(const char *text); bool save(const char *filePath); @@ -156,7 +156,6 @@ struct TextEditInput : public FormEditInput { int _cursorLine; int _indentLevel; int _matchingBrace; - int _lineMarker[MAX_MARKERS]; int _ptY; bool _dirty; }; From 51edd4485bcdc66e9c853fec7cd39d4727fb4aaf Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 8 Oct 2015 22:17:51 +1000 Subject: [PATCH 19/30] UI: fix line wrapped comments --- src/platform/android/jni/runtime.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index bcc88104..00046904 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -738,6 +738,7 @@ void System::completeKeyword(int index) { const char *help = get_focus_edit()->completeKeyword(index); if (help) { runtime->alert(help); + runtime->getOutput()->redraw(); } } } From 4d2a1bf5447dbb7c93bf709a57c2ed9fc50a92fb Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sun, 11 Oct 2015 13:11:11 +1000 Subject: [PATCH 20/30] ANDROID: update freetype --- ChangeLog | 1 + ide/android/AndroidManifest.xml | 2 +- ide/android/assets/main.bas | 2 +- src/common/blib_db.c | 5 ++++- src/platform/android/jni/Android.mk | 8 ++++---- src/platform/android/jni/freetype/Android.mk | 4 ++-- .../src/net/sourceforge/smallbasic/MainActivity.java | 2 +- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9a5fa6de..d3ce151f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Updated program icon Editor line number widget can be used for scrolling Updated editor help display + Fix TSAVE with try/catch 2015-08-26 Editor fixes: diff --git a/ide/android/AndroidManifest.xml b/ide/android/AndroidManifest.xml index b9b56935..861df1f7 100644 --- a/ide/android/AndroidManifest.xml +++ b/ide/android/AndroidManifest.xml @@ -3,7 +3,7 @@ package="net.sourceforge.smallbasic" android:installLocation="preferExternal" android:versionCode="15" - android:versionName="0.11.21"> + android:versionName="0.12.0"> diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index 1a997e24..d850ab93 100644 --- a/ide/android/assets/main.bas +++ b/ide/android/assets/main.bas @@ -85,7 +85,7 @@ sub do_newfile() color 3, 0 cls print boldOn + "Create new program." - print boldOff + "To enable editing, right click then select Editor [ON]" + print boldOff + "To enable editing, display the menu then select Editor [ON]" print local valid_file = false while (!valid_file) diff --git a/src/common/blib_db.c b/src/common/blib_db.c index 290230c6..632bb053 100644 --- a/src/common/blib_db.c +++ b/src/common/blib_db.c @@ -751,9 +751,12 @@ void cmd_fsaveln() { return; } - dev_fopen(handle, (char *)file_name.v.p.ptr, flags); + int success = dev_fopen(handle, (char *)file_name.v.p.ptr, flags); v_free(&file_name); CHK_ERR(FSERR_GENERIC); + if (!success) { + return; + } } if (var_p->type == V_ARRAY) { diff --git a/src/platform/android/jni/Android.mk b/src/platform/android/jni/Android.mk index 3d3919ea..5d9314dd 100644 --- a/src/platform/android/jni/Android.mk +++ b/src/platform/android/jni/Android.mk @@ -7,7 +7,7 @@ JNI_PATH := $(call my-dir) SB_HOME := $(JNI_PATH)/../../../.. -FREETYPE_HOME := $(HOME)/android-sdk/freetype-2.6 +FREETYPE_HOME := $(HOME)/android-sdk/freetype-2.6.1 include $(call all-subdir-makefiles) LOCAL_PATH := $(JNI_PATH) @@ -16,9 +16,9 @@ include $(CLEAR_VARS) LOCAL_MODULE := smallbasic LOCAL_CFLAGS := -DHAVE_CONFIG_H=1 -DLODEPNG_NO_COMPILE_CPP \ -DPIXELFORMAT_RGBA8888 -LOCAL_C_INCLUDES := $(SB_HOME) $(SB_HOME)/src \ - $(FREETYPE_HOME)/freetype/include \ - $(FREETYPE_HOME)/freetype/include/freetype2 +LOCAL_C_INCLUDES := $(SB_HOME) $(SB_HOME)/src \ + $(FREETYPE_HOME)/freetype/include/freetype2 \ + $(FREETYPE_HOME)/freetype/include/freetype2/freetype LOCAL_SRC_FILES := main.cpp \ display.cpp \ runtime.cpp \ diff --git a/src/platform/android/jni/freetype/Android.mk b/src/platform/android/jni/freetype/Android.mk index beece35d..104f63a8 100644 --- a/src/platform/android/jni/freetype/Android.mk +++ b/src/platform/android/jni/freetype/Android.mk @@ -10,8 +10,8 @@ include $(CLEAR_VARS) LOCAL_C_INCLUDES := $(FREETYPE_HOME)/include \ $(FREETYPE_HOME)/builds \ - $(FREETYPE_HOME)/include/config \ - $(FREETYPE_HOME)/include/freetype2 + $(FREETYPE_HOME)/include/freetype/config \ + $(FREETYPE_HOME)/include/freetype LOCAL_MODULE := freetype LOCAL_CFLAGS := -Wall -std=gnu99 \ "-DFT_CONFIG_CONFIG_H=" \ diff --git a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java index 779f967d..455ee438 100644 --- a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java +++ b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java @@ -170,7 +170,7 @@ public void run() { } public String getIPAddress() { - String result = null; + String result = ""; try { for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); From ad1e3c4ced01ebbd7acca71115e07ba0cd74fd84 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Mon, 12 Oct 2015 06:51:20 +1000 Subject: [PATCH 21/30] UI: avoid editing online files --- src/ui/system.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 2de80661..94706a97 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -535,8 +535,8 @@ void System::runMain(const char *mainBasPath) { } } - if (!_mainBas && opt_ide == IDE_INTERNAL && - !isRestart() && loadSource(_loadPath)) { + if (!_mainBas && opt_ide == IDE_INTERNAL && !isRestart() && + _loadPath.indexOf("://", 1) == -1 && loadSource(_loadPath)) { editSource(_loadPath); if (isBack()) { _loadPath.empty(); @@ -680,7 +680,8 @@ void System::setRunning(bool running) { dev_clrkb(); _output->setAutoflush(!opt_show_page); - if (_mainBas || opt_ide != IDE_INTERNAL) { + if (_mainBas || opt_ide != IDE_INTERNAL || + _loadPath.indexOf("://", 1) != -1) { _loadPath.empty(); } _lastEventTime = maGetMilliSecondCount(); From ebcad619c6db6e41ceb6620f3ce82ae654312153 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 13 Oct 2015 06:52:01 +1000 Subject: [PATCH 22/30] UI: fix loop when failing to load net file --- ide/android/assets/main.bas | 3 ++- src/ui/system.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index d850ab93..9b8d33b5 100644 --- a/ide/android/assets/main.bas +++ b/ide/android/assets/main.bas @@ -85,7 +85,8 @@ sub do_newfile() color 3, 0 cls print boldOn + "Create new program." - print boldOff + "To enable editing, display the menu then select Editor [ON]" + print boldOff + "To enable editing, display the menu then select Editor [ON]." + print "Press to leave this screen without making any changes." print local valid_file = false while (!valid_file) diff --git a/src/ui/system.cpp b/src/ui/system.cpp index 94706a97..70e3f917 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -418,7 +418,7 @@ char *System::loadResource(const char *fileName) { memcpy(buffer, var_p->v.p.ptr, len); buffer[len] = '\0'; } else { - systemPrint("\nfailed"); + systemPrint("\nfailed to open %s", fileName); } _output->setStatus(NULL); dev_fclose(handle); @@ -548,12 +548,14 @@ void System::runMain(const char *mainBasPath) { } bool success = execute(_loadPath); + bool networkFile = (_loadPath.indexOf("://", 1) != -1); if (!isClosing() && _overruns) { systemPrint("\nOverruns: %d\n", _overruns); } - if (!isBack() && !isClosing() && (opt_ide != IDE_INTERNAL || success)) { - // load the next network file without displaying the previous result - bool networkFile = (_loadPath.indexOf("://", 1) != -1); + if (!isBack() && !isClosing() && + (opt_ide != IDE_INTERNAL || success || networkFile)) { + // when editing, only pause here when successful, otherwise the editor shows + // the error. load the next network file without displaying the previous result if (!_mainBas && !networkFile) { // display an indication the program has completed showCompletion(success); From 9be583f31267a8082ab5dd512e96796640c045ba Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Wed, 14 Oct 2015 07:08:30 +1000 Subject: [PATCH 23/30] DOC: fix stray quote --- documentation/sbasic_ref.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/sbasic_ref.csv b/documentation/sbasic_ref.csv index ddf3a4ef..4f2f1e5a 100644 --- a/documentation/sbasic_ref.csv +++ b/documentation/sbasic_ref.csv @@ -149,7 +149,7 @@ Language,keyword,SUB,657,"SUB foo (a, b)","Declare a sub procedure. Sub's do not Language,keyword,THEN,658,"THEN","foo = 1: if foo==1 THEN: ? ""one"": fi" Language,keyword,UNIT,659,"UNIT name","Units are a set of procedures, functions and/or variables that can be used by another program or unit." Language,keyword,UNTIL,660,"UNTIL","a = 0: repeat: a++: ? a: UNTIL a = 10" -Language,keyword,USE,661,"USE","Used with various commands for passing a user-defined expression. eg SPLIT s," ",v USE TRIM(x). Trim each element of v." +Language,keyword,USE,661,"USE","Used with various commands for passing a user-defined expression. eg SPLIT s,"" "",v USE TRIM(x). Trim each element of v." Language,operator,AND,662,"a AND b","Logical AND. Right side is not evaluated if left side evaluates to False." Language,operator,BAND,663,"a BAND b","Bitwise AND." Language,operator,BOR,664,"a BOR b","Bitwise OR." From bb5d0b77b9d1b4ad36614f14ce1feadc1bb8ec45 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 15 Oct 2015 07:17:38 +1000 Subject: [PATCH 24/30] UI: avoid unwanted scrolling --- src/ui/textedit.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index f04a514a..31d8922f 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -642,17 +642,16 @@ bool TextEditInput::edit(int key, int screenWidth, int charWidth) { } _cursorRow = getCursorRow(); - if (key == STB_TEXTEDIT_K_UP) { + if (key == STB_TEXTEDIT_K_UP || + key == (int)SB_KEY_SHIFT(STB_TEXTEDIT_K_UP)) { if (_cursorRow == _scroll) { updateScroll(); } - } else if (key == STB_TEXTEDIT_K_DOWN) { + } else { int pageRows = _height / _charHeight; if (_cursorRow - _scroll > pageRows) { updateScroll(); } - } else { - updateScroll(); } findMatchingBrace(); return true; From 3a8049f6b13a8565de8ce3c4b38fa84b5e2e29a1 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 16 Oct 2015 06:51:20 +1000 Subject: [PATCH 25/30] UI: completion includes non keywords --- src/ui/textedit.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 31d8922f..6abf0c66 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -31,6 +31,8 @@ #define TWISTY2_CLOSE " < " #define TWISTY1_LEN 2 #define TWISTY2_LEN 4 +#define HELP_BG 0x73c990 +#define HELP_FG 0x20242a int g_themeId = 0; int g_lineMarker[MAX_MARKERS] = { @@ -1447,7 +1449,7 @@ TextEditHelpWidget::TextEditHelpWidget(TextEditInput *editor, int chW, int chH, _editor(editor), _openPackage(NULL), _openKeyword(-1) { - _theme = new EditTheme(0x73c990, 0x20242a); + _theme = new EditTheme(HELP_BG, HELP_FG); hide(); if (overlay) { _x = editor->_width - (chW * HELP_WIDTH); @@ -1574,12 +1576,31 @@ void TextEditHelpWidget::createCompletionHelp() { char *selection = _editor->getWordBeforeCursor(); int len = selection != NULL ? strlen(selection) : 0; if (len > 0) { + StringList words; for (int i = 0; i < keyword_help_len; i++) { if (strncasecmp(selection, keyword_help[i].keyword, len) == 0) { + words.add(keyword_help[i].keyword); _buf.append(keyword_help[i].keyword); _buf.append("\n", 1); } } + const char *found = strstr(_editor->getText(), selection); + while (found != NULL) { + const char *end = found; + while (!IS_WHITE(*end) && *end != '\0') { + end++; + } + if (end - found > len) { + String next; + next.append(found, end - found); + if (!words.exists(next)) { + words.add(next); + _buf.append(found, end - found); + _buf.append("\n", 1); + } + } + found = strstr(found + len, selection); + } } else { const char *package = NULL; for (int i = 0; i < keyword_help_len; i++) { From c69d716237e4dbaa041943ecec89ccda919d6ace Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 16 Oct 2015 07:32:39 +1000 Subject: [PATCH 26/30] UI: completion includes non keywords --- src/ui/textedit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 6abf0c66..0722ceb2 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -1587,7 +1587,7 @@ void TextEditHelpWidget::createCompletionHelp() { const char *found = strstr(_editor->getText(), selection); while (found != NULL) { const char *end = found; - while (!IS_WHITE(*end) && *end != '\0') { + while (!IS_WHITE(*end) && !ispunct(*end) && *end != '\0') { end++; } if (end - found > len) { From 292e7f3c83304474bd99cefb9bd82b8d6c142978 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Fri, 16 Oct 2015 21:40:09 +1000 Subject: [PATCH 27/30] UI: add copy paste keys --- src/platform/sdl/editor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform/sdl/editor.cpp b/src/platform/sdl/editor.cpp index 032be6dd..0a8dcce0 100644 --- a/src/platform/sdl/editor.cpp +++ b/src/platform/sdl/editor.cpp @@ -113,6 +113,7 @@ void System::editSource(strlib::String &loadPath) { break; case SB_KEY_CTRL('c'): case SB_KEY_CTRL('x'): + case SB_KEY_CTRL(SB_KEY_INSERT): text = widget->copy(event.key == (int)SB_KEY_CTRL('x')); if (text) { setClipboardText(text); @@ -177,6 +178,7 @@ void System::editSource(strlib::String &loadPath) { helpWidget->show(); break; case SB_KEY_CTRL('v'): + case SB_KEY_SHIFT(SB_KEY_INSERT): text = getClipboardText(); widget->paste(text); free(text); From 7c268d8a8d53784436e34472127a78ef907aa3d0 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Sat, 17 Oct 2015 10:35:10 +1000 Subject: [PATCH 28/30] COMMON: update notes --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 698f8c2d..ce0cb8ca 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,15 @@ SmallBASIC is a fast and easy to learn BASIC language interpreter ideal for everyday calculations, scripts and prototypes. SmallBASIC includes trigonometric, matrices and algebra functions, a built in IDE, a powerful string library, system, sound, and graphic commands along with structured programming syntax ## Building the SDL version + +Initial setup on linux +``` + $ sudo apt-get install git autotools-dev automake gcc g++ libsdl2-dev libfreetype6-dev libfontconfig1-dev + $ git clone https://github.com/smallbasic/SmallBASIC.git + $ cd SmallBASIC + $ sh autogen.sh +``` +Build in linux ``` $ ./configure --enable-sdl $ make From 8f005d8f00fb89b4155a39bfe20bd4c090829a15 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Tue, 20 Oct 2015 21:20:57 +1000 Subject: [PATCH 29/30] COMMON: fix LET assignment to map/array field --- ChangeLog | 3 +++ samples/distro-examples/tests/uds.bas | 25 +++++++++++++++++++++++++ src/common/scan.c | 4 +++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d3ce151f..c2eb2fdb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2015-10-20 + Fix LET when assigning a value to a MAP/ARRAY field + 2015-09-15 SDL Update PEN(3) to work more like FLTK Fix display output before PEN diff --git a/samples/distro-examples/tests/uds.bas b/samples/distro-examples/tests/uds.bas index 9e40f2a1..1d2b8fb4 100644 --- a/samples/distro-examples/tests/uds.bas +++ b/samples/distro-examples/tests/uds.bas @@ -111,3 +111,28 @@ next i inner.foo="bar" m.b << inner s = " " + m.b(0).foo + +rem ------------------------------------ + +dim bar.x(2), foo(2) +bar.x(0).barx = 1024 +foo(0).fooY = 999 +if (bar.x(0).barx <> 1024) then + throw "Error 1" +fi + +if (foo(0).fooY <> 999) then + throw "Error 2" +fi + +if (1024 <> bar.x(0).barx) then + throw "Error 3" +fi + +if (999 <> foo(0).fooY) then + throw "Error 4" +fi + +bar.x(1).barx=bar.x(0).barx+976 +bar.x(1).barx/=1000 +if bar.x(1).barx <> 2 then throw "Yuck, I can't read red print on black background." diff --git a/src/common/scan.c b/src/common/scan.c index 91222675..2a2cda04 100644 --- a/src/common/scan.c +++ b/src/common/scan.c @@ -1701,7 +1701,9 @@ char *comp_array_params(char *src, char exitChar) { } break; }; - p++; + if (*p != exitChar) { + p++; + } if (*p == exitChar) { p++; break; From a4e8c2b98a468bc60c9b4edabef2a75997153e29 Mon Sep 17 00:00:00 2001 From: Chris Warren-Smith Date: Thu, 22 Oct 2015 21:02:33 +1000 Subject: [PATCH 30/30] COMMON: fix error handling segfault --- src/common/sberr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/sberr.c b/src/common/sberr.c index cc8a5c28..33f397c2 100644 --- a/src/common/sberr.c +++ b/src/common/sberr.c @@ -413,7 +413,7 @@ void err_throw_str(const char *err) { // throw internal error void err_throw(const char *fmt, ...) { - if (!gsb_last_error) { + if (!gsb_last_error && prog_source) { va_list ap; va_start(ap, fmt); char *err = malloc(SB_TEXTLINE_SIZE + 1);