diff --git a/ChangeLog b/ChangeLog index 553d0bc8..391a48b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2016-02-11 + Added export to mobile command (SDL) + Added Desktop shortcut command (android) + 2015-12-05 Implemented loading recent files via ALT+1 .. ALT+9 Fix potential editor crash with empty support widget diff --git a/configure.ac b/configure.ac index 9f887cd6..4369793a 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.12.3]) +AC_INIT([smallbasic], [0.12.5]) AC_CONFIG_SRCDIR([configure.ac]) AC_CANONICAL_TARGET diff --git a/ide/android/AndroidManifest.xml b/ide/android/AndroidManifest.xml index 266a066b..e1b671ff 100644 --- a/ide/android/AndroidManifest.xml +++ b/ide/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="19" + android:versionName="0.12.5"> @@ -64,5 +64,6 @@ + diff --git a/ide/android/assets/main.bas b/ide/android/assets/main.bas index ab7c2f53..284ee3e1 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.12.3" + print "Version 0.12.5" print print "Copyright (c) 2002-2015 Chris Warren-Smith" print "Copyright (c) 1999-2006 Nic Christopoulos" + chr(10) diff --git a/src/platform/android/Makefile.am b/src/platform/android/Makefile.am index c2423910..3f612be8 100644 --- a/src/platform/android/Makefile.am +++ b/src/platform/android/Makefile.am @@ -17,7 +17,7 @@ test: ant-build-test (cd ../../../ide/android && \ adb -a logcat -c && \ adb -a shell am start net.sourceforge.smallbasic/net.sourceforge.smallbasic.MainActivity && \ - adb -a logcat) + adb -a logcat DEBUG:I smallbasic:I AndroidRuntime:E *:S) clean-ant: (cd ../../../ide/android && ant -quiet clean) diff --git a/src/platform/android/jni/runtime.cpp b/src/platform/android/jni/runtime.cpp index 5f4002cf..1795d9ef 100644 --- a/src/platform/android/jni/runtime.cpp +++ b/src/platform/android/jni/runtime.cpp @@ -89,6 +89,7 @@ void handleCommand(android_app *app, int32_t cmd) { case APP_CMD_GAINED_FOCUS: trace("gainedFocus"); runtime->setFocus(true); + runtime->redraw(); break; case APP_CMD_LOST_FOCUS: trace("lostFocus"); @@ -138,7 +139,7 @@ extern "C" JNIEXPORT void JNICALL Java_net_sourceforge_smallbasic_MainActivity_r extern "C" JNIEXPORT void JNICALL Java_net_sourceforge_smallbasic_MainActivity_onResize (JNIEnv *env, jclass jclazz, jint width, jint height) { - if (runtime != NULL && runtime->isActive() && os_graphics) { + if (runtime != NULL && !runtime->isClosing() && runtime->isActive() && os_graphics) { runtime->onResize(width, height); } } @@ -176,6 +177,10 @@ Runtime::~Runtime() { pthread_mutex_destroy(&_mutex); } +void Runtime::addShortcut(const char *path) { + setString("addShortcut", path); +} + void Runtime::alert(const char *title, const char *message) { logEntered(); @@ -200,8 +205,7 @@ void Runtime::alert(const char *title, bool longDuration) { _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;Z)V"); + jmethodID method = env->GetMethodID(clazz, "showToast", "(Ljava/lang/String;Z)V"); env->CallVoidMethod(_app->activity->clazz, method, titleString, longDuration); env->DeleteLocalRef(clazz); env->DeleteLocalRef(titleString); diff --git a/src/platform/android/jni/runtime.h b/src/platform/android/jni/runtime.h index 6af9bd5b..ded3cb35 100644 --- a/src/platform/android/jni/runtime.h +++ b/src/platform/android/jni/runtime.h @@ -21,6 +21,7 @@ struct Runtime : public System { Runtime(android_app *app); virtual ~Runtime(); + void addShortcut(const char *path); void alert(const char *title, const char *message); void alert(const char *title, bool longDuration=true); int ask(const char *title, const char *prompt, bool cancel); diff --git a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java index d9df0ee5..319cee7f 100644 --- a/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java +++ b/src/platform/android/src/net/sourceforge/smallbasic/MainActivity.java @@ -84,6 +84,23 @@ public class MainActivity extends NativeActivity { public static native void onResize(int width, int height); public static native void runFile(String fileName); + public void addShortcut(final String path) { + Intent shortcut = new Intent(getApplicationContext(), MainActivity.class); + shortcut.setAction(Intent.ACTION_MAIN); + shortcut.setData(Uri.parse("smallbasic://" + path)); + Intent intent = new Intent(); + int index = path.lastIndexOf('/'); + String name = (index == -1) ? path : path.substring(index + 1); + intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcut); + intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name); + intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, + Intent.ShortcutIconResource.fromContext(getApplicationContext(), + R.drawable.ic_launcher)); + intent.putExtra("duplicate", false); + intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); + getApplicationContext().sendBroadcast(intent); + } + public int ask(final String title, final String prompt, final boolean cancel) { final AskResult result = new AskResult(); final Activity activity = this; diff --git a/src/platform/sdl/editor.cpp b/src/platform/sdl/editor.cpp index 31f83dd7..d003a8b1 100644 --- a/src/platform/sdl/editor.cpp +++ b/src/platform/sdl/editor.cpp @@ -9,12 +9,16 @@ #include "config.h" #include "common/sbapp.h" +#include "common/fs_socket_client.h" #include "ui/textedit.h" #include "platform/sdl/runtime.h" #include "platform/sdl/settings.h" using namespace strlib; +String g_exportAddr; +String g_exportToken; + void onlineHelp(Runtime *runtime, TextEditInput *widget) { char path[100]; const char *nodeId = widget->getNodeId(); @@ -60,6 +64,27 @@ void showRecentFiles(TextEditHelpWidget *helpWidget, String &loadPath) { helpWidget->setText(fileList); } +void exportBuffer(AnsiWidget *out, const char *text, String &dest, String &token) { + char buffer[PATH_MAX]; + dev_file_t f; + memset(&f, 0, sizeof(dev_file_t)); + + sprintf(f.name, "SOCL:%s\n", dest.c_str()); + if (dest.indexOf(':', 0) != -1 && sockcl_open(&f)) { + sprintf(buffer, "# %s\n", token.c_str()); + sockcl_write(&f, (byte *)buffer, strlen(buffer)); + if (!sockcl_write(&f, (byte *)text, strlen(text))) { + sprintf(buffer, "Failed to write: %s", dest.c_str()); + } else { + sprintf(buffer, "Exported file to %s", dest.c_str()); + } + sockcl_close(&f); + } else { + sprintf(buffer, "Failed to open: %s", dest.c_str()); + } + out->setStatus(buffer); +} + void System::editSource(String &loadPath) { logEntered(); @@ -73,6 +98,9 @@ void System::editSource(String &loadPath) { TextEditInput *widget = editWidget; String dirtyFile; String cleanFile; + enum InputMode { + kInit, kExportAddr, kExportToken + } inputMode = kInit; setupStatus(dirtyFile, cleanFile, loadPath); _modifiedTime = getModifiedTime(); @@ -124,7 +152,6 @@ void System::editSource(String &loadPath) { } switch (event.key) { - case SB_KEY_F(3): case SB_KEY_F(8): case SB_KEY_F(10): case SB_KEY_F(11): @@ -168,6 +195,22 @@ void System::editSource(String &loadPath) { redraw = false; onlineHelp((Runtime *)this, editWidget); break; + case SB_KEY_F(4): + if (editWidget->getTextLength() && g_exportAddr.length() && g_exportToken.length()) { + exportBuffer(_output, editWidget->getText(), g_exportAddr, g_exportToken); + break; + } + // else fallthru to F3 handler + case SB_KEY_F(3): + if (editWidget->getTextLength()) { + saveFile(editWidget, loadPath); + _output->setStatus("Export to mobile SmallBASIC. Enter :"); + widget = helpWidget; + helpWidget->createLineEdit(g_exportAddr); + helpWidget->show(); + inputMode = kExportAddr; + } + break; case SB_KEY_F(5): saveFile(editWidget, loadPath); _output->setStatus("Debug. F6=Step, F7=Continue, Esc=Close"); @@ -269,6 +312,25 @@ void System::editSource(String &loadPath) { if (helpWidget->replaceMode()) { _output->setStatus("Replace string with. Esc=Close"); dirty = editWidget->isDirty(); + } else if (helpWidget->lineEditMode() && helpWidget->getTextLength()) { + switch (inputMode) { + case kExportAddr: + g_exportAddr = helpWidget->getText(); + inputMode = kExportToken; + helpWidget->createLineEdit(g_exportToken); + _output->setStatus("Enter token. Esc=Close"); + break; + case kExportToken: + g_exportToken = helpWidget->getText(); + inputMode = kInit; + widget = editWidget; + exportBuffer(_output, editWidget->getText(), g_exportAddr, g_exportToken); + helpWidget->hide(); + break; + default: + break; + } + redraw = true; } else if (helpWidget->closeOnEnter() && helpWidget->isVisible()) { if (helpWidget->replaceDoneMode()) { _output->setStatus(dirtyFile); diff --git a/src/platform/sdl/runtime.h b/src/platform/sdl/runtime.h index 5d45b42b..030293e3 100644 --- a/src/platform/sdl/runtime.h +++ b/src/platform/sdl/runtime.h @@ -21,6 +21,7 @@ struct Runtime : public System { Runtime(SDL_Window *window); virtual ~Runtime(); + void addShortcut(const char *) {} void alert(const char *title, const char *message); int ask(const char *title, const char *prompt, bool cancel); void browseFile(const char *url); diff --git a/src/ui/graphics.cpp b/src/ui/graphics.cpp index 8fc55026..9ff2fc38 100644 --- a/src/ui/graphics.cpp +++ b/src/ui/graphics.cpp @@ -314,6 +314,11 @@ int Graphics::getPixel(Canvas *canvas, int posX, int posY) { && posY < canvas->_h - 1) { pixel_t *line = canvas->getLine(posY); result = line[posX]; +#if defined(PIXELFORMAT_RGBA8888) + uint8_t r,g,b; + GET_RGB2(result, r, g, b); + result = SET_RGB(r, g, b); +#endif } return result; } diff --git a/src/ui/system.cpp b/src/ui/system.cpp index d53b5437..af881048 100644 --- a/src/ui/system.cpp +++ b/src/ui/system.cpp @@ -41,7 +41,8 @@ #define MENU_DEBUG 18 #define MENU_OUTPUT 19 #define MENU_HELP 20 -#define MENU_SIZE 21 +#define MENU_SHORTCUT 21 +#define MENU_SIZE 22 #define MENU_COMPETION_0 (MENU_SIZE + 1) #define MENU_COMPETION_1 (MENU_SIZE + 2) #define MENU_COMPETION_2 (MENU_SIZE + 3) @@ -342,6 +343,11 @@ void System::handleMenu(MAEvent &event) { event.type = EVENT_TYPE_KEY_PRESSED; event.key = SB_KEY_F(1); break; + case MENU_SHORTCUT: + if (_activeFile.length() > 0) { + addShortcut(_activeFile.c_str()); + } + break; case MENU_COMPETION_0: completeKeyword(0); break; @@ -631,22 +637,22 @@ void System::saveFile(TextEditInput *edit, strlib::String &path) { void System::setBack() { if (_userScreenId != -1) { - // restore user screen + // return (back) from user screen, (view source) _output->selectBackScreen(_userScreenId); _output->selectFrontScreen(_userScreenId); _userScreenId = -1; - } - - // quit app when shell is active - setExit(_mainBas); - - // follow history when available and not exiting - if (!_mainBas) { - // remove the current item - _history.pop(); - if (_history.peek() != NULL) { - _loadPath.empty(); - _loadPath.append(_history.peek()); + } else { + // quit app when shell is active + setExit(_mainBas); + + // follow history when available and not exiting + if (!_mainBas) { + // remove the current item + _history.pop(); + if (_history.peek() != NULL) { + _loadPath.empty(); + _loadPath.append(_history.peek()); + } } } } @@ -865,6 +871,12 @@ void System::showMenu() { items->add(new String(buffer)); _systemMenu[index++] = MENU_EDITMODE; } +#if !defined(_SDL) + if (!_mainBas && _activeFile.length() > 0) { + items->add(new String("Desktop Shortcut")); + _systemMenu[index++] = MENU_SHORTCUT; + } +#endif sprintf(buffer, "Audio [%s]", (opt_mute_audio ? "OFF" : "ON")); items->add(new String(buffer)); _systemMenu[index++] = MENU_AUDIO; diff --git a/src/ui/system.h b/src/ui/system.h index 3bea273a..5210729e 100755 --- a/src/ui/system.h +++ b/src/ui/system.h @@ -53,6 +53,7 @@ struct System { kHand, kArrow, kIBeam }; + virtual void addShortcut(const char *path) = 0; virtual void alert(const char *title, const char *message) = 0; virtual int ask(const char *title, const char *prompt, bool cancel=true) = 0; virtual void debugStart(TextEditInput *edit, const char *file) = 0; diff --git a/src/ui/textedit.cpp b/src/ui/textedit.cpp index 5ed76699..3279dd85 100644 --- a/src/ui/textedit.cpp +++ b/src/ui/textedit.cpp @@ -108,6 +108,7 @@ const char *helpText = "TAB indent line\n" "F1,A-h keyword help\n" "F2 online help\n" + "F3,F4 export\n" "F5 debug\n" "F9, C-r run\n"; @@ -1528,7 +1529,6 @@ bool TextEditHelpWidget::closeOnEnter() const { bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { bool result = false; - switch (_mode) { case kSearch: result = TextEditInput::edit(key, screenWidth, charWidth); @@ -1558,6 +1558,11 @@ bool TextEditHelpWidget::edit(int key, int screenWidth, int charWidth) { _editor->gotoLine(_buf._buffer); } break; + case kLineEdit: + if (key != SB_KEY_ENTER) { + result = TextEditInput::edit(key, screenWidth, charWidth); + } + break; default: switch (key) { case STB_TEXTEDIT_K_LEFT: @@ -1690,6 +1695,13 @@ void TextEditHelpWidget::createHelp() { _buf.append(helpText, strlen(helpText)); } +void TextEditHelpWidget::createLineEdit(const char *value) { + reset(kLineEdit); + if (value && value[0]) { + _buf.append(value, strlen(value)); + } +} + void TextEditHelpWidget::createKeywordIndex() { char *keyword = _editor->getWordBeforeCursor(); reset(kHelpKeyword); diff --git a/src/ui/textedit.h b/src/ui/textedit.h index 29c01072..24955287 100644 --- a/src/ui/textedit.h +++ b/src/ui/textedit.h @@ -181,13 +181,15 @@ struct TextEditHelpWidget : public TextEditInput { kReplace, kReplaceDone, kGotoLine, - kMessage + kMessage, + kLineEdit }; void clicked(int x, int y, bool pressed); void createCompletionHelp(); void createGotoLine(); void createHelp(); + void createLineEdit(const char *value); void createKeywordIndex(); void createMessage() { reset(kMessage); } void createOutline(); @@ -198,6 +200,7 @@ struct TextEditHelpWidget : public TextEditInput { void resize(int w, int h) { _x = w - _width; _height = h; } void reset(HelpMode mode); bool closeOnEnter() const; + bool lineEditMode() const { return _mode == kLineEdit; } bool messageMode() const { return _mode == kMessage; } bool replaceMode() const { return _mode == kReplace; } bool replaceDoneMode() const { return _mode == kReplaceDone; }